Home | History | Annotate | Download | only in storage_monitor
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <windows.h>
      6 #include <dbt.h>
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/memory/ref_counted.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/run_loop.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/synchronization/waitable_event.h"
     16 #include "components/storage_monitor/mock_removable_storage_observer.h"
     17 #include "components/storage_monitor/portable_device_watcher_win.h"
     18 #include "components/storage_monitor/removable_device_constants.h"
     19 #include "components/storage_monitor/storage_info.h"
     20 #include "components/storage_monitor/storage_monitor_win.h"
     21 #include "components/storage_monitor/test_portable_device_watcher_win.h"
     22 #include "components/storage_monitor/test_storage_monitor.h"
     23 #include "components/storage_monitor/test_storage_monitor_win.h"
     24 #include "components/storage_monitor/test_volume_mount_watcher_win.h"
     25 #include "components/storage_monitor/volume_mount_watcher_win.h"
     26 #include "content/public/browser/browser_thread.h"
     27 #include "content/public/test/test_browser_thread_bundle.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 using base::ASCIIToUTF16;
     31 using content::BrowserThread;
     32 
     33 typedef std::vector<int> DeviceIndices;
     34 
     35 // StorageMonitorWinTest -------------------------------------------------------
     36 
     37 namespace storage_monitor {
     38 
     39 class StorageMonitorWinTest : public testing::Test {
     40  public:
     41   StorageMonitorWinTest();
     42   virtual ~StorageMonitorWinTest();
     43 
     44  protected:
     45   // testing::Test:
     46   virtual void SetUp() OVERRIDE;
     47   virtual void TearDown() OVERRIDE;
     48 
     49   void PreAttachDevices();
     50 
     51   // Runs all the pending tasks on UI thread, FILE thread and blocking thread.
     52   void RunUntilIdle();
     53 
     54   void DoMassStorageDeviceAttachedTest(const DeviceIndices& device_indices);
     55   void DoMassStorageDevicesDetachedTest(const DeviceIndices& device_indices);
     56 
     57   // Injects a device attach or detach change (depending on the value of
     58   // |test_attach|) and tests that the appropriate handler is called.
     59   void DoMTPDeviceTest(const base::string16& pnp_device_id, bool test_attach);
     60 
     61   // Gets the MTP details of the storage specified by the |storage_device_id|.
     62   // On success, returns true and fills in |pnp_device_id| and
     63   // |storage_object_id|.
     64   bool GetMTPStorageInfo(const std::string& storage_device_id,
     65                          base::string16* pnp_device_id,
     66                          base::string16* storage_object_id);
     67 
     68   scoped_ptr<TestStorageMonitorWin> monitor_;
     69 
     70   // Weak pointer; owned by the device notifications class.
     71   TestVolumeMountWatcherWin* volume_mount_watcher_;
     72 
     73   MockRemovableStorageObserver observer_;
     74 
     75  private:
     76   content::TestBrowserThreadBundle thread_bundle_;
     77 
     78   DISALLOW_COPY_AND_ASSIGN(StorageMonitorWinTest);
     79 };
     80 
     81 StorageMonitorWinTest::StorageMonitorWinTest() {
     82 }
     83 
     84 StorageMonitorWinTest::~StorageMonitorWinTest() {
     85 }
     86 
     87 void StorageMonitorWinTest::SetUp() {
     88   volume_mount_watcher_ = new TestVolumeMountWatcherWin;
     89   monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
     90                                            new TestPortableDeviceWatcherWin));
     91 
     92   monitor_->Init();
     93   RunUntilIdle();
     94   monitor_->AddObserver(&observer_);
     95 }
     96 
     97 void StorageMonitorWinTest::TearDown() {
     98   RunUntilIdle();
     99   monitor_->RemoveObserver(&observer_);
    100   volume_mount_watcher_->ShutdownWorkerPool();
    101 
    102   // Windows storage monitor must be destroyed on the same thread
    103   // as construction.
    104   monitor_.reset();
    105 }
    106 
    107 void StorageMonitorWinTest::PreAttachDevices() {
    108   monitor_.reset();
    109   volume_mount_watcher_ = new TestVolumeMountWatcherWin;
    110   volume_mount_watcher_->SetAttachedDevicesFake();
    111 
    112   int expect_attach_calls = 0;
    113   std::vector<base::FilePath> initial_devices =
    114       volume_mount_watcher_->GetAttachedDevicesCallback().Run();
    115   for (std::vector<base::FilePath>::const_iterator it = initial_devices.begin();
    116        it != initial_devices.end(); ++it) {
    117     bool removable;
    118     ASSERT_TRUE(volume_mount_watcher_->GetDeviceRemovable(*it, &removable));
    119     if (removable)
    120       expect_attach_calls++;
    121   }
    122 
    123   monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
    124                                            new TestPortableDeviceWatcherWin));
    125 
    126   monitor_->AddObserver(&observer_);
    127   monitor_->Init();
    128 
    129   EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
    130 
    131   // This dance is because attachment bounces through a couple of
    132   // closures, which need to be executed to finish the process.
    133   RunUntilIdle();
    134   volume_mount_watcher_->FlushWorkerPoolForTesting();
    135   RunUntilIdle();
    136 
    137   std::vector<base::FilePath> checked_devices =
    138       volume_mount_watcher_->devices_checked();
    139   sort(checked_devices.begin(), checked_devices.end());
    140   EXPECT_EQ(initial_devices, checked_devices);
    141   EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
    142   EXPECT_EQ(0, observer_.detach_calls());
    143 }
    144 
    145 void StorageMonitorWinTest::RunUntilIdle() {
    146   volume_mount_watcher_->FlushWorkerPoolForTesting();
    147   base::RunLoop().RunUntilIdle();
    148 }
    149 
    150 void StorageMonitorWinTest::DoMassStorageDeviceAttachedTest(
    151     const DeviceIndices& device_indices) {
    152   DEV_BROADCAST_VOLUME volume_broadcast;
    153   volume_broadcast.dbcv_size = sizeof(volume_broadcast);
    154   volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
    155   volume_broadcast.dbcv_unitmask = 0x0;
    156   volume_broadcast.dbcv_flags = 0x0;
    157 
    158   int expect_attach_calls = observer_.attach_calls();
    159   for (DeviceIndices::const_iterator it = device_indices.begin();
    160        it != device_indices.end(); ++it) {
    161     volume_broadcast.dbcv_unitmask |= 0x1 << *it;
    162     bool removable;
    163     ASSERT_TRUE(volume_mount_watcher_->GetDeviceRemovable(
    164         VolumeMountWatcherWin::DriveNumberToFilePath(*it), &removable));
    165     if (removable)
    166       expect_attach_calls++;
    167   }
    168   monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
    169                                reinterpret_cast<DWORD>(&volume_broadcast));
    170 
    171   RunUntilIdle();
    172   volume_mount_watcher_->FlushWorkerPoolForTesting();
    173   RunUntilIdle();
    174 
    175   EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
    176   EXPECT_EQ(0, observer_.detach_calls());
    177 }
    178 
    179 void StorageMonitorWinTest::DoMassStorageDevicesDetachedTest(
    180     const DeviceIndices& device_indices) {
    181   DEV_BROADCAST_VOLUME volume_broadcast;
    182   volume_broadcast.dbcv_size = sizeof(volume_broadcast);
    183   volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
    184   volume_broadcast.dbcv_unitmask = 0x0;
    185   volume_broadcast.dbcv_flags = 0x0;
    186 
    187   int pre_attach_calls = observer_.attach_calls();
    188   int expect_detach_calls = 0;
    189   for (DeviceIndices::const_iterator it = device_indices.begin();
    190        it != device_indices.end(); ++it) {
    191     volume_broadcast.dbcv_unitmask |= 0x1 << *it;
    192     StorageInfo info;
    193     ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(
    194         VolumeMountWatcherWin::DriveNumberToFilePath(*it), &info));
    195     if (StorageInfo::IsRemovableDevice(info.device_id()))
    196       ++expect_detach_calls;
    197   }
    198   monitor_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE,
    199                                reinterpret_cast<DWORD>(&volume_broadcast));
    200   RunUntilIdle();
    201   EXPECT_EQ(pre_attach_calls, observer_.attach_calls());
    202   EXPECT_EQ(expect_detach_calls, observer_.detach_calls());
    203 }
    204 
    205 void StorageMonitorWinTest::DoMTPDeviceTest(const base::string16& pnp_device_id,
    206                                             bool test_attach) {
    207   GUID guidDevInterface = GUID_NULL;
    208   HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface);
    209   if (FAILED(hr))
    210     return;
    211 
    212   size_t device_id_size = pnp_device_id.size() * sizeof(base::char16);
    213   size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + device_id_size;
    214   scoped_ptr<DEV_BROADCAST_DEVICEINTERFACE, base::FreeDeleter>
    215       dev_interface_broadcast(
    216           static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size)));
    217   DCHECK(dev_interface_broadcast.get());
    218   ZeroMemory(dev_interface_broadcast.get(), size);
    219   dev_interface_broadcast->dbcc_size = size;
    220   dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    221   dev_interface_broadcast->dbcc_classguid = guidDevInterface;
    222   memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(),
    223          device_id_size);
    224 
    225   int expect_attach_calls = observer_.attach_calls();
    226   int expect_detach_calls = observer_.detach_calls();
    227   PortableDeviceWatcherWin::StorageObjectIDs storage_object_ids =
    228       TestPortableDeviceWatcherWin::GetMTPStorageObjectIds(pnp_device_id);
    229   for (PortableDeviceWatcherWin::StorageObjectIDs::const_iterator it =
    230        storage_object_ids.begin(); it != storage_object_ids.end(); ++it) {
    231     std::string unique_id;
    232     base::string16 name;
    233     base::string16 location;
    234     TestPortableDeviceWatcherWin::GetMTPStorageDetails(pnp_device_id, *it,
    235                                                        &location, &unique_id,
    236                                                        &name);
    237     if (test_attach && !name.empty() && !unique_id.empty())
    238       expect_attach_calls++;
    239     else if (!name.empty() && !unique_id.empty())
    240       expect_detach_calls++;
    241   }
    242 
    243   monitor_->InjectDeviceChange(
    244       test_attach ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE,
    245       reinterpret_cast<DWORD>(dev_interface_broadcast.get()));
    246 
    247   RunUntilIdle();
    248   EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
    249   EXPECT_EQ(expect_detach_calls, observer_.detach_calls());
    250 }
    251 
    252 bool StorageMonitorWinTest::GetMTPStorageInfo(
    253     const std::string& storage_device_id,
    254     base::string16* pnp_device_id,
    255     base::string16* storage_object_id) {
    256   return monitor_->GetMTPStorageInfoFromDeviceId(storage_device_id,
    257                                                  pnp_device_id,
    258                                                  storage_object_id);
    259 }
    260 
    261 TEST_F(StorageMonitorWinTest, RandomMessage) {
    262   monitor_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL);
    263   RunUntilIdle();
    264 }
    265 
    266 TEST_F(StorageMonitorWinTest, DevicesAttached) {
    267   DeviceIndices device_indices;
    268   device_indices.push_back(1);  // B
    269   device_indices.push_back(5);  // F
    270   device_indices.push_back(7);  // H
    271   device_indices.push_back(13);  // N
    272   DoMassStorageDeviceAttachedTest(device_indices);
    273 
    274   StorageInfo info;
    275   EXPECT_TRUE(monitor_->volume_mount_watcher()->GetDeviceInfo(
    276       base::FilePath(ASCIIToUTF16("F:\\")), &info));
    277   EXPECT_EQ(ASCIIToUTF16("F:\\"), info.location());
    278   EXPECT_EQ("dcim:\\\\?\\Volume{F0000000-0000-0000-0000-000000000000}\\",
    279             info.device_id());
    280   EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info.storage_label());
    281 
    282   EXPECT_FALSE(monitor_->GetStorageInfoForPath(
    283       base::FilePath(ASCIIToUTF16("G:\\")), &info));
    284   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    285       base::FilePath(ASCIIToUTF16("F:\\")), &info));
    286   StorageInfo info1;
    287   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    288       base::FilePath(ASCIIToUTF16("F:\\subdir")), &info1));
    289   StorageInfo info2;
    290   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    291       base::FilePath(ASCIIToUTF16("F:\\subdir\\sub")), &info2));
    292   EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info.storage_label());
    293   EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info1.storage_label());
    294   EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info2.storage_label());
    295 }
    296 
    297 TEST_F(StorageMonitorWinTest, PathMountDevices) {
    298   PreAttachDevices();
    299   int init_storages = monitor_->GetAllAvailableStorages().size();
    300 
    301   volume_mount_watcher_->AddDeviceForTesting(
    302       base::FilePath(FILE_PATH_LITERAL("F:\\mount1")),
    303       "dcim:mount1", L"mount1", 100);
    304   volume_mount_watcher_->AddDeviceForTesting(
    305       base::FilePath(FILE_PATH_LITERAL("F:\\mount1\\subdir")),
    306       "dcim:mount1subdir", L"mount1subdir", 100);
    307   volume_mount_watcher_->AddDeviceForTesting(
    308       base::FilePath(FILE_PATH_LITERAL("F:\\mount2")),
    309       "dcim:mount2", L"mount2", 100);
    310   RunUntilIdle();
    311   EXPECT_EQ(init_storages + 3, monitor_->GetAllAvailableStorages().size());
    312 
    313   StorageInfo info;
    314   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    315       base::FilePath(ASCIIToUTF16("F:\\dir")), &info));
    316   EXPECT_EQ(L"F:\\ Drive", info.GetDisplayName(false));
    317   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    318       base::FilePath(ASCIIToUTF16("F:\\mount1")), &info));
    319   EXPECT_EQ(L"mount1", info.GetDisplayName(false));
    320   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    321       base::FilePath(ASCIIToUTF16("F:\\mount1\\dir")), &info));
    322   EXPECT_EQ(L"mount1", info.GetDisplayName(false));
    323   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    324       base::FilePath(ASCIIToUTF16("F:\\mount2\\dir")), &info));
    325   EXPECT_EQ(L"mount2", info.GetDisplayName(false));
    326   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    327       base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir")), &info));
    328   EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
    329   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    330       base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir")), &info));
    331   EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
    332   EXPECT_TRUE(monitor_->GetStorageInfoForPath(
    333       base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir\\dir")), &info));
    334   EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
    335 }
    336 
    337 TEST_F(StorageMonitorWinTest, DevicesAttachedHighBoundary) {
    338   DeviceIndices device_indices;
    339   device_indices.push_back(25);
    340 
    341   DoMassStorageDeviceAttachedTest(device_indices);
    342 }
    343 
    344 TEST_F(StorageMonitorWinTest, DevicesAttachedLowBoundary) {
    345   DeviceIndices device_indices;
    346   device_indices.push_back(0);
    347 
    348   DoMassStorageDeviceAttachedTest(device_indices);
    349 }
    350 
    351 TEST_F(StorageMonitorWinTest, DevicesAttachedAdjacentBits) {
    352   DeviceIndices device_indices;
    353   device_indices.push_back(0);
    354   device_indices.push_back(1);
    355   device_indices.push_back(2);
    356   device_indices.push_back(3);
    357 
    358   DoMassStorageDeviceAttachedTest(device_indices);
    359 }
    360 
    361 TEST_F(StorageMonitorWinTest, DevicesDetached) {
    362   PreAttachDevices();
    363 
    364   DeviceIndices device_indices;
    365   device_indices.push_back(1);
    366   device_indices.push_back(5);
    367   device_indices.push_back(7);
    368   device_indices.push_back(13);
    369 
    370   DoMassStorageDevicesDetachedTest(device_indices);
    371 }
    372 
    373 TEST_F(StorageMonitorWinTest, DevicesDetachedHighBoundary) {
    374   PreAttachDevices();
    375 
    376   DeviceIndices device_indices;
    377   device_indices.push_back(25);
    378 
    379   DoMassStorageDevicesDetachedTest(device_indices);
    380 }
    381 
    382 TEST_F(StorageMonitorWinTest, DevicesDetachedLowBoundary) {
    383   PreAttachDevices();
    384 
    385   DeviceIndices device_indices;
    386   device_indices.push_back(0);
    387 
    388   DoMassStorageDevicesDetachedTest(device_indices);
    389 }
    390 
    391 TEST_F(StorageMonitorWinTest, DevicesDetachedAdjacentBits) {
    392   PreAttachDevices();
    393 
    394   DeviceIndices device_indices;
    395   device_indices.push_back(0);
    396   device_indices.push_back(1);
    397   device_indices.push_back(2);
    398   device_indices.push_back(3);
    399 
    400   DoMassStorageDevicesDetachedTest(device_indices);
    401 }
    402 
    403 TEST_F(StorageMonitorWinTest, DuplicateAttachCheckSuppressed) {
    404   // Make sure the original C: mount notification makes it all the
    405   // way through.
    406   RunUntilIdle();
    407   volume_mount_watcher_->FlushWorkerPoolForTesting();
    408   RunUntilIdle();
    409 
    410   volume_mount_watcher_->BlockDeviceCheckForTesting();
    411   base::FilePath kAttachedDevicePath =
    412       VolumeMountWatcherWin::DriveNumberToFilePath(8);  // I:
    413 
    414   DEV_BROADCAST_VOLUME volume_broadcast;
    415   volume_broadcast.dbcv_size = sizeof(volume_broadcast);
    416   volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
    417   volume_broadcast.dbcv_flags = 0x0;
    418   volume_broadcast.dbcv_unitmask = 0x100;  // I: drive
    419   monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
    420                                reinterpret_cast<DWORD>(&volume_broadcast));
    421 
    422   EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
    423 
    424   // Re-attach the same volume. We haven't released the mock device check
    425   // event, so there'll be pending calls in the UI thread to finish the
    426   // device check notification, blocking the duplicate device injection.
    427   monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
    428                                reinterpret_cast<DWORD>(&volume_broadcast));
    429 
    430   EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
    431   volume_mount_watcher_->ReleaseDeviceCheck();
    432   RunUntilIdle();
    433   volume_mount_watcher_->ReleaseDeviceCheck();
    434 
    435   // Now let all attach notifications finish running. We'll only get one
    436   // finish-attach call.
    437   volume_mount_watcher_->FlushWorkerPoolForTesting();
    438   RunUntilIdle();
    439 
    440   const std::vector<base::FilePath>& checked_devices =
    441       volume_mount_watcher_->devices_checked();
    442   ASSERT_EQ(1u, checked_devices.size());
    443   EXPECT_EQ(kAttachedDevicePath, checked_devices[0]);
    444 
    445   // We'll receive a duplicate check now that the first check has fully cleared.
    446   monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
    447                                reinterpret_cast<DWORD>(&volume_broadcast));
    448   volume_mount_watcher_->FlushWorkerPoolForTesting();
    449   volume_mount_watcher_->ReleaseDeviceCheck();
    450   RunUntilIdle();
    451 
    452   ASSERT_EQ(2u, checked_devices.size());
    453   EXPECT_EQ(kAttachedDevicePath, checked_devices[0]);
    454   EXPECT_EQ(kAttachedDevicePath, checked_devices[1]);
    455 }
    456 
    457 TEST_F(StorageMonitorWinTest, DeviceInfoForPath) {
    458   PreAttachDevices();
    459 
    460   StorageInfo device_info;
    461   // An invalid path.
    462   EXPECT_FALSE(monitor_->GetStorageInfoForPath(base::FilePath(L"COM1:\\"),
    463                                                &device_info));
    464 
    465   // An unconnected removable device.
    466   EXPECT_FALSE(monitor_->GetStorageInfoForPath(base::FilePath(L"E:\\"),
    467                                                &device_info));
    468 
    469   // A connected removable device.
    470   base::FilePath removable_device(L"F:\\");
    471   EXPECT_TRUE(monitor_->GetStorageInfoForPath(removable_device, &device_info));
    472 
    473   StorageInfo info;
    474   ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(removable_device, &info));
    475   EXPECT_TRUE(StorageInfo::IsRemovableDevice(info.device_id()));
    476   EXPECT_EQ(info.device_id(), device_info.device_id());
    477   EXPECT_EQ(info.GetDisplayName(false), device_info.GetDisplayName(false));
    478   EXPECT_EQ(info.location(), device_info.location());
    479   EXPECT_EQ(1000000, info.total_size_in_bytes());
    480 
    481   // A fixed device.
    482   base::FilePath fixed_device(L"N:\\");
    483   EXPECT_TRUE(monitor_->GetStorageInfoForPath(fixed_device, &device_info));
    484 
    485   ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(
    486       fixed_device, &info));
    487   EXPECT_FALSE(StorageInfo::IsRemovableDevice(info.device_id()));
    488   EXPECT_EQ(info.device_id(), device_info.device_id());
    489   EXPECT_EQ(info.GetDisplayName(false), device_info.GetDisplayName(false));
    490   EXPECT_EQ(info.location(), device_info.location());
    491 }
    492 
    493 // Test to verify basic MTP storage attach and detach notifications.
    494 TEST_F(StorageMonitorWinTest, MTPDeviceBasicAttachDetach) {
    495   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, true);
    496   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, false);
    497 }
    498 
    499 // When a MTP storage device with invalid storage label and id is
    500 // attached/detached, there should not be any device attach/detach
    501 // notifications.
    502 TEST_F(StorageMonitorWinTest, MTPDeviceWithInvalidInfo) {
    503   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo,
    504                   true);
    505   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo,
    506                   false);
    507 }
    508 
    509 // Attach a device with two data partitions. Verify that attach/detach
    510 // notifications are sent out for each removable storage.
    511 TEST_F(StorageMonitorWinTest, MTPDeviceWithMultipleStorageObjects) {
    512   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages,
    513                   true);
    514   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages,
    515                   false);
    516 }
    517 
    518 TEST_F(StorageMonitorWinTest, DriveNumberToFilePath) {
    519   EXPECT_EQ(L"A:\\", VolumeMountWatcherWin::DriveNumberToFilePath(0).value());
    520   EXPECT_EQ(L"Y:\\", VolumeMountWatcherWin::DriveNumberToFilePath(24).value());
    521   EXPECT_EQ(L"", VolumeMountWatcherWin::DriveNumberToFilePath(-1).value());
    522   EXPECT_EQ(L"", VolumeMountWatcherWin::DriveNumberToFilePath(199).value());
    523 }
    524 
    525 // Given a MTP storage persistent id, GetMTPStorageInfo() should fetch the
    526 // device interface path and local storage object identifier.
    527 TEST_F(StorageMonitorWinTest, GetMTPStorageInfoFromDeviceId) {
    528   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, true);
    529   PortableDeviceWatcherWin::StorageObjects storage_objects =
    530       TestPortableDeviceWatcherWin::GetDeviceStorageObjects(
    531           TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo);
    532   for (PortableDeviceWatcherWin::StorageObjects::const_iterator it =
    533            storage_objects.begin();
    534        it != storage_objects.end(); ++it) {
    535     base::string16 pnp_device_id;
    536     base::string16 storage_object_id;
    537     ASSERT_TRUE(GetMTPStorageInfo(it->object_persistent_id, &pnp_device_id,
    538                                   &storage_object_id));
    539     base::string16 expected(
    540         TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo);
    541     EXPECT_EQ(expected, pnp_device_id);
    542     EXPECT_EQ(it->object_persistent_id,
    543               TestPortableDeviceWatcherWin::GetMTPStorageUniqueId(
    544                   pnp_device_id, storage_object_id));
    545   }
    546   DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, false);
    547 }
    548 
    549 }  // namespace storage_monitor
    550