123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/storage_monitor/storage_monitor_chromeos.h"
- #include <stdint.h>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "ash/components/disks/disk.h"
- #include "ash/components/disks/mock_disk_mount_manager.h"
- #include "base/bind.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/run_loop.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/task_environment.h"
- #include "components/storage_monitor/mock_removable_storage_observer.h"
- #include "components/storage_monitor/removable_device_constants.h"
- #include "components/storage_monitor/storage_info.h"
- #include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
- #include "components/storage_monitor/test_storage_monitor.h"
- #include "content/public/test/browser_task_environment.h"
- #include "mojo/public/cpp/bindings/pending_remote.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace storage_monitor {
- namespace {
- using ::ash::disks::Disk;
- using ::ash::disks::DiskMountManager;
- using testing::_;
- const char kDevice1[] = "/dev/d1";
- const char kDevice1Name[] = "d1";
- const char kDevice2[] = "/dev/disk/d2";
- const char kDevice2Name[] = "d2";
- const char kEmptyDeviceLabel[] = "";
- const char kMountPointA[] = "mnt_a";
- const char kMountPointB[] = "mnt_b";
- const char kSDCardDeviceName1[] = "8.6 MB Amy_SD";
- const char kSDCardDeviceName2[] = "8.6 MB SD Card";
- const char kSDCardMountPoint1[] = "media/removable/Amy_SD";
- const char kSDCardMountPoint2[] = "media/removable/SD Card";
- const char kProductName[] = "Z101";
- const char kUniqueId1[] = "FFFF-FFFF";
- const char kUniqueId2[] = "FFFF-FF0F";
- const char kVendorName[] = "CompanyA";
- const char kFileSystemType[] = "exfat";
- uint64_t kDevice1SizeInBytes = 113048;
- uint64_t kDevice2SizeInBytes = 212312;
- uint64_t kSDCardSizeInBytes = 9000000;
- std::string GetDCIMDeviceId(const std::string& unique_id) {
- return StorageInfo::MakeDeviceId(
- StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
- kFSUniqueIdPrefix + unique_id);
- }
- // A test version of StorageMonitorCros that exposes protected methods to tests.
- class TestStorageMonitorCros : public StorageMonitorCros {
- public:
- TestStorageMonitorCros() {}
- TestStorageMonitorCros(const TestStorageMonitorCros&) = delete;
- TestStorageMonitorCros& operator=(const TestStorageMonitorCros&) = delete;
- ~TestStorageMonitorCros() override {}
- void Init() override {
- mojo::PendingRemote<device::mojom::MtpManager> pending_fake_mtp_manager;
- auto* fake_mtp_manager =
- TestMediaTransferProtocolManagerChromeOS::GetFakeMtpManager();
- fake_mtp_manager->AddReceiver(
- pending_fake_mtp_manager.InitWithNewPipeAndPassReceiver());
- SetMediaTransferProtocolManagerForTest(std::move(pending_fake_mtp_manager));
- StorageMonitorCros::Init();
- }
- void OnMountEvent(DiskMountManager::MountEvent event,
- ash::MountError error_code,
- const DiskMountManager::MountPoint& mount_info) override {
- StorageMonitorCros::OnMountEvent(event, error_code, mount_info);
- }
- void OnBootDeviceDiskEvent(DiskMountManager::DiskEvent event,
- const Disk& disk) override {
- StorageMonitorCros::OnBootDeviceDiskEvent(event, disk);
- }
- bool GetStorageInfoForPath(const base::FilePath& path,
- StorageInfo* device_info) const override {
- return StorageMonitorCros::GetStorageInfoForPath(path, device_info);
- }
- void EjectDevice(const std::string& device_id,
- base::OnceCallback<void(EjectStatus)> callback) override {
- StorageMonitorCros::EjectDevice(device_id, std::move(callback));
- }
- };
- // Wrapper class to test StorageMonitorCros.
- class StorageMonitorCrosTest : public testing::Test {
- public:
- StorageMonitorCrosTest();
- StorageMonitorCrosTest(const StorageMonitorCrosTest&) = delete;
- StorageMonitorCrosTest& operator=(const StorageMonitorCrosTest&) = delete;
- ~StorageMonitorCrosTest() override;
- void EjectNotify(StorageMonitor::EjectStatus status);
- protected:
- // testing::Test:
- void SetUp() override;
- void TearDown() override;
- void MountDevice(ash::MountError error_code,
- const DiskMountManager::MountPoint& mount_info,
- const std::string& unique_id,
- const std::string& device_label,
- const std::string& vendor_name,
- const std::string& product_name,
- ash::DeviceType device_type,
- uint64_t device_size_in_bytes);
- void UnmountDevice(ash::MountError error_code,
- const DiskMountManager::MountPoint& mount_info);
- uint64_t GetDeviceStorageSize(const std::string& device_location);
- // Create a directory named |dir| relative to the test directory.
- // Set |with_dcim_dir| to true if the created directory will have a "DCIM"
- // subdirectory.
- // Returns the full path to the created directory on success, or an empty
- // path on failure.
- base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir);
- MockRemovableStorageObserver& observer() {
- return *mock_storage_observer_;
- }
- TestStorageMonitorCros* monitor_;
- // Owned by DiskMountManager.
- ash::disks::MockDiskMountManager* disk_mount_manager_mock_;
- StorageMonitor::EjectStatus status_;
- private:
- content::BrowserTaskEnvironment task_environment_;
- // Temporary directory for created test data.
- base::ScopedTempDir scoped_temp_dir_;
- // Objects that talks with StorageMonitorCros.
- std::unique_ptr<MockRemovableStorageObserver> mock_storage_observer_;
- };
- StorageMonitorCrosTest::StorageMonitorCrosTest()
- : monitor_(NULL),
- disk_mount_manager_mock_(NULL),
- status_(StorageMonitor::EJECT_FAILURE) {}
- StorageMonitorCrosTest::~StorageMonitorCrosTest() {
- }
- void StorageMonitorCrosTest::SetUp() {
- ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- disk_mount_manager_mock_ = new ash::disks::MockDiskMountManager();
- DiskMountManager::InitializeForTesting(disk_mount_manager_mock_);
- disk_mount_manager_mock_->SetupDefaultReplies();
- mock_storage_observer_ = std::make_unique<MockRemovableStorageObserver>();
- // Initialize the test subject.
- TestStorageMonitor::Destroy();
- monitor_ = new TestStorageMonitorCros();
- std::unique_ptr<StorageMonitor> pass_monitor(monitor_);
- StorageMonitor::SetStorageMonitorForTesting(std::move(pass_monitor));
- monitor_->Init();
- monitor_->AddObserver(mock_storage_observer_.get());
- }
- void StorageMonitorCrosTest::TearDown() {
- monitor_->RemoveObserver(mock_storage_observer_.get());
- monitor_ = NULL;
- disk_mount_manager_mock_ = NULL;
- DiskMountManager::Shutdown();
- task_environment_.RunUntilIdle();
- }
- void StorageMonitorCrosTest::MountDevice(
- ash::MountError error_code,
- const DiskMountManager::MountPoint& mount_info,
- const std::string& unique_id,
- const std::string& device_label,
- const std::string& vendor_name,
- const std::string& product_name,
- ash::DeviceType device_type,
- uint64_t device_size_in_bytes) {
- if (error_code == ash::MountError::kNone) {
- disk_mount_manager_mock_->CreateDiskEntryForMountDevice(
- mount_info, unique_id, device_label, vendor_name, product_name,
- device_type, device_size_in_bytes, false /* is_parent */,
- true /* has_media */, false /* on_boot_device */,
- true /* on_removable_device */, kFileSystemType);
- }
- monitor_->OnMountEvent(DiskMountManager::MOUNTING, error_code, mount_info);
- task_environment_.RunUntilIdle();
- }
- void StorageMonitorCrosTest::UnmountDevice(
- ash::MountError error_code,
- const DiskMountManager::MountPoint& mount_info) {
- monitor_->OnMountEvent(DiskMountManager::UNMOUNTING, error_code, mount_info);
- if (error_code == ash::MountError::kNone)
- disk_mount_manager_mock_->RemoveDiskEntryForMountDevice(mount_info);
- task_environment_.RunUntilIdle();
- }
- uint64_t StorageMonitorCrosTest::GetDeviceStorageSize(
- const std::string& device_location) {
- StorageInfo info;
- if (!monitor_->GetStorageInfoForPath(base::FilePath(device_location), &info))
- return 0;
- return info.total_size_in_bytes();
- }
- base::FilePath StorageMonitorCrosTest::CreateMountPoint(
- const std::string& dir, bool with_dcim_dir) {
- base::FilePath return_path(scoped_temp_dir_.GetPath());
- return_path = return_path.AppendASCII(dir);
- base::FilePath path(return_path);
- if (with_dcim_dir)
- path = path.Append(kDCIMDirectoryName);
- if (!base::CreateDirectory(path))
- return base::FilePath();
- return return_path;
- }
- void StorageMonitorCrosTest::EjectNotify(StorageMonitor::EjectStatus status) {
- status_ = status;
- }
- // Simple test case where we attach and detach a media device.
- TEST_F(StorageMonitorCrosTest, BasicAttachDetach) {
- base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
- ASSERT_FALSE(mount_path1.empty());
- DiskMountManager::MountPoint mount_info{kDevice1, mount_path1.value(),
- ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId1,
- kDevice1Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
- UnmountDevice(ash::MountError::kNone, mount_info);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_detached().device_id());
- base::FilePath mount_path2 = CreateMountPoint(kMountPointB, true);
- ASSERT_FALSE(mount_path2.empty());
- DiskMountManager::MountPoint mount_info2{kDevice2, mount_path2.value(),
- ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info2,
- kUniqueId2,
- kDevice2Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice2SizeInBytes);
- EXPECT_EQ(2, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path2.value(), observer().last_attached().location());
- UnmountDevice(ash::MountError::kNone, mount_info2);
- EXPECT_EQ(2, observer().attach_calls());
- EXPECT_EQ(2, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_detached().device_id());
- }
- // Removable mass storage devices with no dcim folder are also recognized.
- TEST_F(StorageMonitorCrosTest, NoDCIM) {
- testing::Sequence mock_sequence;
- base::FilePath mount_path = CreateMountPoint(kMountPointA, false);
- const std::string kUniqueId = "FFFF-FFFF";
- ASSERT_FALSE(mount_path.empty());
- DiskMountManager::MountPoint mount_info{kDevice1, mount_path.value(),
- ash::MountType::kDevice};
- const std::string device_id = StorageInfo::MakeDeviceId(
- StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM,
- kFSUniqueIdPrefix + kUniqueId);
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId,
- kDevice1Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(device_id, observer().last_attached().device_id());
- EXPECT_EQ(mount_path.value(), observer().last_attached().location());
- }
- // Non device mounts and mount errors are ignored.
- TEST_F(StorageMonitorCrosTest, Ignore) {
- testing::Sequence mock_sequence;
- base::FilePath mount_path = CreateMountPoint(kMountPointA, true);
- const std::string kUniqueId = "FFFF-FFFF";
- ASSERT_FALSE(mount_path.empty());
- // Mount error.
- DiskMountManager::MountPoint mount_info{kDevice1, mount_path.value(),
- ash::MountType::kDevice};
- MountDevice(ash::MountError::kUnknown,
- mount_info,
- kUniqueId,
- kDevice1Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(0, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- // Not a device
- mount_info.mount_type = ash::MountType::kArchive;
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId,
- kDevice1Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(0, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- // Unsupported file system.
- mount_info.mount_type = ash::MountType::kDevice;
- mount_info.mount_condition =
- ash::disks::MountCondition::kUnsupportedFilesystem;
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId,
- kDevice1Name,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(0, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- }
- TEST_F(StorageMonitorCrosTest, SDCardAttachDetach) {
- base::FilePath mount_path1 = CreateMountPoint(kSDCardMountPoint1, true);
- ASSERT_FALSE(mount_path1.empty());
- DiskMountManager::MountPoint mount_info1{
- kSDCardDeviceName1, mount_path1.value(), ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info1,
- kUniqueId2,
- kSDCardDeviceName1,
- kVendorName,
- kProductName,
- ash::DeviceType::kSD,
- kSDCardSizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
- UnmountDevice(ash::MountError::kNone, mount_info1);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_detached().device_id());
- base::FilePath mount_path2 = CreateMountPoint(kSDCardMountPoint2, true);
- ASSERT_FALSE(mount_path2.empty());
- DiskMountManager::MountPoint mount_info2{
- kSDCardDeviceName2, mount_path2.value(), ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info2,
- kUniqueId2,
- kSDCardDeviceName2,
- kVendorName,
- kProductName,
- ash::DeviceType::kSD,
- kSDCardSizeInBytes);
- EXPECT_EQ(2, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path2.value(), observer().last_attached().location());
- UnmountDevice(ash::MountError::kNone, mount_info2);
- EXPECT_EQ(2, observer().attach_calls());
- EXPECT_EQ(2, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
- observer().last_detached().device_id());
- }
- TEST_F(StorageMonitorCrosTest, AttachDeviceWithEmptyLabel) {
- base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
- ASSERT_FALSE(mount_path1.empty());
- DiskMountManager::MountPoint mount_info{
- kEmptyDeviceLabel, mount_path1.value(), ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId1,
- kEmptyDeviceLabel,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
- UnmountDevice(ash::MountError::kNone, mount_info);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_detached().device_id());
- }
- TEST_F(StorageMonitorCrosTest, GetStorageSize) {
- base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
- ASSERT_FALSE(mount_path1.empty());
- DiskMountManager::MountPoint mount_info{
- kEmptyDeviceLabel, mount_path1.value(), ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId1,
- kEmptyDeviceLabel,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_attached().device_id());
- EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
- EXPECT_EQ(kDevice1SizeInBytes, GetDeviceStorageSize(mount_path1.value()));
- UnmountDevice(ash::MountError::kNone, mount_info);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
- observer().last_detached().device_id());
- }
- TEST_F(StorageMonitorCrosTest, EjectTest) {
- base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
- ASSERT_FALSE(mount_path1.empty());
- DiskMountManager::MountPoint mount_info{
- kEmptyDeviceLabel, mount_path1.value(), ash::MountType::kDevice};
- MountDevice(ash::MountError::kNone,
- mount_info,
- kUniqueId1,
- kEmptyDeviceLabel,
- kVendorName,
- kProductName,
- ash::DeviceType::kUSB,
- kDevice1SizeInBytes);
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- // testing::Invoke doesn't handle move-only types, so use a lambda instead.
- ON_CALL(*disk_mount_manager_mock_, UnmountPath(_, _))
- .WillByDefault([](const std::string& location,
- DiskMountManager::UnmountPathCallback cb) {
- std::move(cb).Run(ash::MountError::kNone);
- });
- EXPECT_CALL(*disk_mount_manager_mock_,
- UnmountPath(observer().last_attached().location(), _));
- monitor_->EjectDevice(observer().last_attached().device_id(),
- base::BindOnce(&StorageMonitorCrosTest::EjectNotify,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(StorageMonitor::EJECT_OK, status_);
- }
- TEST_F(StorageMonitorCrosTest, FixedStroageTest) {
- const std::string uuid = "fixed1-uuid";
- const std::string mount_point = "/mnt/stateful_partition";
- // Fixed storage (stateful partition) added.
- const std::string label = "fixed1";
- std::unique_ptr<const Disk> disk = Disk::Builder()
- .SetMountPath(mount_point)
- .SetDeviceLabel(label)
- .SetFileSystemUUID(uuid)
- .Build();
- monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_ADDED,
- *disk);
- std::vector<StorageInfo> disks = monitor_->GetAllAvailableStorages();
- ASSERT_EQ(1U, disks.size());
- EXPECT_EQ(mount_point, disks[0].location());
- EXPECT_EQ(base::ASCIIToUTF16(label), disks[0].storage_label());
- // Fixed storage (not stateful partition) added - ignore.
- std::unique_ptr<const Disk> ignored_disk =
- Disk::Builder()
- .SetMountPath("usr/share/OEM")
- .SetDeviceLabel("fixed2")
- .SetFileSystemUUID("fixed2-uuid")
- .Build();
- monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_ADDED,
- *ignored_disk);
- disks = monitor_->GetAllAvailableStorages();
- ASSERT_EQ(1U, disks.size());
- EXPECT_EQ(mount_point, disks[0].location());
- EXPECT_EQ(base::ASCIIToUTF16(label), disks[0].storage_label());
- // Fixed storage (stateful partition) removed.
- monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_REMOVED,
- *disk);
- disks = monitor_->GetAllAvailableStorages();
- EXPECT_EQ(0U, disks.size());
- }
- } // namespace
- } // namespace storage_monitor
|