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