storage_monitor_win_unittest.cc 20 KB

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