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.
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"
30 using base::ASCIIToUTF16
;
31 using content::BrowserThread
;
33 typedef std::vector
<int> DeviceIndices
;
35 // StorageMonitorWinTest -------------------------------------------------------
37 namespace storage_monitor
{
39 class StorageMonitorWinTest
: public testing::Test
{
41 StorageMonitorWinTest();
42 virtual ~StorageMonitorWinTest();
46 virtual void SetUp() override
;
47 virtual void TearDown() override
;
49 void PreAttachDevices();
51 // Runs all the pending tasks on UI thread, FILE thread and blocking thread.
54 void DoMassStorageDeviceAttachedTest(const DeviceIndices
& device_indices
);
55 void DoMassStorageDevicesDetachedTest(const DeviceIndices
& device_indices
);
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
);
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
);
68 scoped_ptr
<TestStorageMonitorWin
> monitor_
;
70 // Weak pointer; owned by the device notifications class.
71 TestVolumeMountWatcherWin
* volume_mount_watcher_
;
73 MockRemovableStorageObserver observer_
;
76 content::TestBrowserThreadBundle thread_bundle_
;
78 DISALLOW_COPY_AND_ASSIGN(StorageMonitorWinTest
);
81 StorageMonitorWinTest::StorageMonitorWinTest() {
84 StorageMonitorWinTest::~StorageMonitorWinTest() {
87 void StorageMonitorWinTest::SetUp() {
88 volume_mount_watcher_
= new TestVolumeMountWatcherWin
;
89 monitor_
.reset(new TestStorageMonitorWin(volume_mount_watcher_
,
90 new TestPortableDeviceWatcherWin
));
94 monitor_
->AddObserver(&observer_
);
97 void StorageMonitorWinTest::TearDown() {
99 monitor_
->RemoveObserver(&observer_
);
101 // Windows storage monitor must be destroyed on the same thread
106 void StorageMonitorWinTest::PreAttachDevices() {
108 volume_mount_watcher_
= new TestVolumeMountWatcherWin
;
109 volume_mount_watcher_
->SetAttachedDevicesFake();
111 int expect_attach_calls
= 0;
112 std::vector
<base::FilePath
> initial_devices
=
113 volume_mount_watcher_
->GetAttachedDevicesCallback().Run();
114 for (std::vector
<base::FilePath
>::const_iterator it
= initial_devices
.begin();
115 it
!= initial_devices
.end(); ++it
) {
117 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceRemovable(*it
, &removable
));
119 expect_attach_calls
++;
122 monitor_
.reset(new TestStorageMonitorWin(volume_mount_watcher_
,
123 new TestPortableDeviceWatcherWin
));
125 monitor_
->AddObserver(&observer_
);
128 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
130 // This dance is because attachment bounces through a couple of
131 // closures, which need to be executed to finish the process.
133 volume_mount_watcher_
->FlushWorkerPoolForTesting();
136 std::vector
<base::FilePath
> checked_devices
=
137 volume_mount_watcher_
->devices_checked();
138 sort(checked_devices
.begin(), checked_devices
.end());
139 EXPECT_EQ(initial_devices
, checked_devices
);
140 EXPECT_EQ(expect_attach_calls
, observer_
.attach_calls());
141 EXPECT_EQ(0, observer_
.detach_calls());
144 void StorageMonitorWinTest::RunUntilIdle() {
145 volume_mount_watcher_
->FlushWorkerPoolForTesting();
146 base::RunLoop().RunUntilIdle();
149 void StorageMonitorWinTest::DoMassStorageDeviceAttachedTest(
150 const DeviceIndices
& device_indices
) {
151 DEV_BROADCAST_VOLUME volume_broadcast
;
152 volume_broadcast
.dbcv_size
= sizeof(volume_broadcast
);
153 volume_broadcast
.dbcv_devicetype
= DBT_DEVTYP_VOLUME
;
154 volume_broadcast
.dbcv_unitmask
= 0x0;
155 volume_broadcast
.dbcv_flags
= 0x0;
157 int expect_attach_calls
= observer_
.attach_calls();
158 for (DeviceIndices::const_iterator it
= device_indices
.begin();
159 it
!= device_indices
.end(); ++it
) {
160 volume_broadcast
.dbcv_unitmask
|= 0x1 << *it
;
162 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceRemovable(
163 VolumeMountWatcherWin::DriveNumberToFilePath(*it
), &removable
));
165 expect_attach_calls
++;
167 monitor_
->InjectDeviceChange(DBT_DEVICEARRIVAL
,
168 reinterpret_cast<DWORD
>(&volume_broadcast
));
171 volume_mount_watcher_
->FlushWorkerPoolForTesting();
174 EXPECT_EQ(expect_attach_calls
, observer_
.attach_calls());
175 EXPECT_EQ(0, observer_
.detach_calls());
178 void StorageMonitorWinTest::DoMassStorageDevicesDetachedTest(
179 const DeviceIndices
& device_indices
) {
180 DEV_BROADCAST_VOLUME volume_broadcast
;
181 volume_broadcast
.dbcv_size
= sizeof(volume_broadcast
);
182 volume_broadcast
.dbcv_devicetype
= DBT_DEVTYP_VOLUME
;
183 volume_broadcast
.dbcv_unitmask
= 0x0;
184 volume_broadcast
.dbcv_flags
= 0x0;
186 int pre_attach_calls
= observer_
.attach_calls();
187 int expect_detach_calls
= 0;
188 for (DeviceIndices::const_iterator it
= device_indices
.begin();
189 it
!= device_indices
.end(); ++it
) {
190 volume_broadcast
.dbcv_unitmask
|= 0x1 << *it
;
192 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceInfo(
193 VolumeMountWatcherWin::DriveNumberToFilePath(*it
), &info
));
194 if (StorageInfo::IsRemovableDevice(info
.device_id()))
195 ++expect_detach_calls
;
197 monitor_
->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE
,
198 reinterpret_cast<DWORD
>(&volume_broadcast
));
200 EXPECT_EQ(pre_attach_calls
, observer_
.attach_calls());
201 EXPECT_EQ(expect_detach_calls
, observer_
.detach_calls());
204 void StorageMonitorWinTest::DoMTPDeviceTest(const base::string16
& pnp_device_id
,
206 GUID guidDevInterface
= GUID_NULL
;
207 HRESULT hr
= CLSIDFromString(kWPDDevInterfaceGUID
, &guidDevInterface
);
211 size_t device_id_size
= pnp_device_id
.size() * sizeof(base::char16
);
212 size_t size
= sizeof(DEV_BROADCAST_DEVICEINTERFACE
) + device_id_size
;
213 scoped_ptr
<DEV_BROADCAST_DEVICEINTERFACE
, base::FreeDeleter
>
214 dev_interface_broadcast(
215 static_cast<DEV_BROADCAST_DEVICEINTERFACE
*>(malloc(size
)));
216 DCHECK(dev_interface_broadcast
.get());
217 ZeroMemory(dev_interface_broadcast
.get(), size
);
218 dev_interface_broadcast
->dbcc_size
= size
;
219 dev_interface_broadcast
->dbcc_devicetype
= DBT_DEVTYP_DEVICEINTERFACE
;
220 dev_interface_broadcast
->dbcc_classguid
= guidDevInterface
;
221 memcpy(dev_interface_broadcast
->dbcc_name
, pnp_device_id
.data(),
224 int expect_attach_calls
= observer_
.attach_calls();
225 int expect_detach_calls
= observer_
.detach_calls();
226 PortableDeviceWatcherWin::StorageObjectIDs storage_object_ids
=
227 TestPortableDeviceWatcherWin::GetMTPStorageObjectIds(pnp_device_id
);
228 for (PortableDeviceWatcherWin::StorageObjectIDs::const_iterator it
=
229 storage_object_ids
.begin(); it
!= storage_object_ids
.end(); ++it
) {
230 std::string unique_id
;
232 base::string16 location
;
233 TestPortableDeviceWatcherWin::GetMTPStorageDetails(pnp_device_id
, *it
,
234 &location
, &unique_id
,
236 if (test_attach
&& !name
.empty() && !unique_id
.empty())
237 expect_attach_calls
++;
238 else if (!name
.empty() && !unique_id
.empty())
239 expect_detach_calls
++;
242 monitor_
->InjectDeviceChange(
243 test_attach
? DBT_DEVICEARRIVAL
: DBT_DEVICEREMOVECOMPLETE
,
244 reinterpret_cast<DWORD
>(dev_interface_broadcast
.get()));
247 EXPECT_EQ(expect_attach_calls
, observer_
.attach_calls());
248 EXPECT_EQ(expect_detach_calls
, observer_
.detach_calls());
251 bool StorageMonitorWinTest::GetMTPStorageInfo(
252 const std::string
& storage_device_id
,
253 base::string16
* pnp_device_id
,
254 base::string16
* storage_object_id
) {
255 return monitor_
->GetMTPStorageInfoFromDeviceId(storage_device_id
,
260 TEST_F(StorageMonitorWinTest
, RandomMessage
) {
261 monitor_
->InjectDeviceChange(DBT_DEVICEQUERYREMOVE
, NULL
);
265 TEST_F(StorageMonitorWinTest
, DevicesAttached
) {
266 DeviceIndices device_indices
;
267 device_indices
.push_back(1); // B
268 device_indices
.push_back(5); // F
269 device_indices
.push_back(7); // H
270 device_indices
.push_back(13); // N
271 DoMassStorageDeviceAttachedTest(device_indices
);
274 EXPECT_TRUE(monitor_
->volume_mount_watcher()->GetDeviceInfo(
275 base::FilePath(ASCIIToUTF16("F:\\")), &info
));
276 EXPECT_EQ(ASCIIToUTF16("F:\\"), info
.location());
277 EXPECT_EQ("dcim:\\\\?\\Volume{F0000000-0000-0000-0000-000000000000}\\",
279 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info
.storage_label());
281 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(
282 base::FilePath(ASCIIToUTF16("G:\\")), &info
));
283 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
284 base::FilePath(ASCIIToUTF16("F:\\")), &info
));
286 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
287 base::FilePath(ASCIIToUTF16("F:\\subdir")), &info1
));
289 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
290 base::FilePath(ASCIIToUTF16("F:\\subdir\\sub")), &info2
));
291 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info
.storage_label());
292 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info1
.storage_label());
293 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info2
.storage_label());
296 TEST_F(StorageMonitorWinTest
, PathMountDevices
) {
298 int init_storages
= monitor_
->GetAllAvailableStorages().size();
300 volume_mount_watcher_
->AddDeviceForTesting(
301 base::FilePath(FILE_PATH_LITERAL("F:\\mount1")),
302 "dcim:mount1", L
"mount1", 100);
303 volume_mount_watcher_
->AddDeviceForTesting(
304 base::FilePath(FILE_PATH_LITERAL("F:\\mount1\\subdir")),
305 "dcim:mount1subdir", L
"mount1subdir", 100);
306 volume_mount_watcher_
->AddDeviceForTesting(
307 base::FilePath(FILE_PATH_LITERAL("F:\\mount2")),
308 "dcim:mount2", L
"mount2", 100);
310 EXPECT_EQ(init_storages
+ 3, monitor_
->GetAllAvailableStorages().size());
313 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
314 base::FilePath(ASCIIToUTF16("F:\\dir")), &info
));
315 EXPECT_EQ(L
"F:\\ Drive", info
.GetDisplayName(false));
316 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
317 base::FilePath(ASCIIToUTF16("F:\\mount1")), &info
));
318 EXPECT_EQ(L
"mount1", info
.GetDisplayName(false));
319 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
320 base::FilePath(ASCIIToUTF16("F:\\mount1\\dir")), &info
));
321 EXPECT_EQ(L
"mount1", info
.GetDisplayName(false));
322 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
323 base::FilePath(ASCIIToUTF16("F:\\mount2\\dir")), &info
));
324 EXPECT_EQ(L
"mount2", info
.GetDisplayName(false));
325 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
326 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir")), &info
));
327 EXPECT_EQ(L
"mount1subdir", info
.GetDisplayName(false));
328 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
329 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir")), &info
));
330 EXPECT_EQ(L
"mount1subdir", info
.GetDisplayName(false));
331 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
332 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir\\dir")), &info
));
333 EXPECT_EQ(L
"mount1subdir", info
.GetDisplayName(false));
336 TEST_F(StorageMonitorWinTest
, DevicesAttachedHighBoundary
) {
337 DeviceIndices device_indices
;
338 device_indices
.push_back(25);
340 DoMassStorageDeviceAttachedTest(device_indices
);
343 TEST_F(StorageMonitorWinTest
, DevicesAttachedLowBoundary
) {
344 DeviceIndices device_indices
;
345 device_indices
.push_back(0);
347 DoMassStorageDeviceAttachedTest(device_indices
);
350 TEST_F(StorageMonitorWinTest
, DevicesAttachedAdjacentBits
) {
351 DeviceIndices device_indices
;
352 device_indices
.push_back(0);
353 device_indices
.push_back(1);
354 device_indices
.push_back(2);
355 device_indices
.push_back(3);
357 DoMassStorageDeviceAttachedTest(device_indices
);
360 TEST_F(StorageMonitorWinTest
, DevicesDetached
) {
363 DeviceIndices device_indices
;
364 device_indices
.push_back(1);
365 device_indices
.push_back(5);
366 device_indices
.push_back(7);
367 device_indices
.push_back(13);
369 DoMassStorageDevicesDetachedTest(device_indices
);
372 TEST_F(StorageMonitorWinTest
, DevicesDetachedHighBoundary
) {
375 DeviceIndices device_indices
;
376 device_indices
.push_back(25);
378 DoMassStorageDevicesDetachedTest(device_indices
);
381 TEST_F(StorageMonitorWinTest
, DevicesDetachedLowBoundary
) {
384 DeviceIndices device_indices
;
385 device_indices
.push_back(0);
387 DoMassStorageDevicesDetachedTest(device_indices
);
390 TEST_F(StorageMonitorWinTest
, DevicesDetachedAdjacentBits
) {
393 DeviceIndices device_indices
;
394 device_indices
.push_back(0);
395 device_indices
.push_back(1);
396 device_indices
.push_back(2);
397 device_indices
.push_back(3);
399 DoMassStorageDevicesDetachedTest(device_indices
);
402 TEST_F(StorageMonitorWinTest
, DuplicateAttachCheckSuppressed
) {
403 // Make sure the original C: mount notification makes it all the
406 volume_mount_watcher_
->FlushWorkerPoolForTesting();
409 volume_mount_watcher_
->BlockDeviceCheckForTesting();
410 base::FilePath kAttachedDevicePath
=
411 VolumeMountWatcherWin::DriveNumberToFilePath(8); // I:
413 DEV_BROADCAST_VOLUME volume_broadcast
;
414 volume_broadcast
.dbcv_size
= sizeof(volume_broadcast
);
415 volume_broadcast
.dbcv_devicetype
= DBT_DEVTYP_VOLUME
;
416 volume_broadcast
.dbcv_flags
= 0x0;
417 volume_broadcast
.dbcv_unitmask
= 0x100; // I: drive
418 monitor_
->InjectDeviceChange(DBT_DEVICEARRIVAL
,
419 reinterpret_cast<DWORD
>(&volume_broadcast
));
421 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
423 // Re-attach the same volume. We haven't released the mock device check
424 // event, so there'll be pending calls in the UI thread to finish the
425 // device check notification, blocking the duplicate device injection.
426 monitor_
->InjectDeviceChange(DBT_DEVICEARRIVAL
,
427 reinterpret_cast<DWORD
>(&volume_broadcast
));
429 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
430 volume_mount_watcher_
->ReleaseDeviceCheck();
432 volume_mount_watcher_
->ReleaseDeviceCheck();
434 // Now let all attach notifications finish running. We'll only get one
435 // finish-attach call.
436 volume_mount_watcher_
->FlushWorkerPoolForTesting();
439 const std::vector
<base::FilePath
>& checked_devices
=
440 volume_mount_watcher_
->devices_checked();
441 ASSERT_EQ(1u, checked_devices
.size());
442 EXPECT_EQ(kAttachedDevicePath
, checked_devices
[0]);
444 // We'll receive a duplicate check now that the first check has fully cleared.
445 monitor_
->InjectDeviceChange(DBT_DEVICEARRIVAL
,
446 reinterpret_cast<DWORD
>(&volume_broadcast
));
447 volume_mount_watcher_
->FlushWorkerPoolForTesting();
448 volume_mount_watcher_
->ReleaseDeviceCheck();
451 ASSERT_EQ(2u, checked_devices
.size());
452 EXPECT_EQ(kAttachedDevicePath
, checked_devices
[0]);
453 EXPECT_EQ(kAttachedDevicePath
, checked_devices
[1]);
456 TEST_F(StorageMonitorWinTest
, DeviceInfoForPath
) {
459 StorageInfo device_info
;
461 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(base::FilePath(L
"COM1:\\"),
464 // An unconnected removable device.
465 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(base::FilePath(L
"E:\\"),
468 // A connected removable device.
469 base::FilePath
removable_device(L
"F:\\");
470 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(removable_device
, &device_info
));
473 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceInfo(removable_device
, &info
));
474 EXPECT_TRUE(StorageInfo::IsRemovableDevice(info
.device_id()));
475 EXPECT_EQ(info
.device_id(), device_info
.device_id());
476 EXPECT_EQ(info
.GetDisplayName(false), device_info
.GetDisplayName(false));
477 EXPECT_EQ(info
.location(), device_info
.location());
478 EXPECT_EQ(1000000, info
.total_size_in_bytes());
481 base::FilePath
fixed_device(L
"N:\\");
482 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(fixed_device
, &device_info
));
484 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceInfo(
485 fixed_device
, &info
));
486 EXPECT_FALSE(StorageInfo::IsRemovableDevice(info
.device_id()));
487 EXPECT_EQ(info
.device_id(), device_info
.device_id());
488 EXPECT_EQ(info
.GetDisplayName(false), device_info
.GetDisplayName(false));
489 EXPECT_EQ(info
.location(), device_info
.location());
492 // Test to verify basic MTP storage attach and detach notifications.
493 TEST_F(StorageMonitorWinTest
, MTPDeviceBasicAttachDetach
) {
494 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
, true);
495 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
, false);
498 // When a MTP storage device with invalid storage label and id is
499 // attached/detached, there should not be any device attach/detach
501 TEST_F(StorageMonitorWinTest
, MTPDeviceWithInvalidInfo
) {
502 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo
,
504 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo
,
508 // Attach a device with two data partitions. Verify that attach/detach
509 // notifications are sent out for each removable storage.
510 TEST_F(StorageMonitorWinTest
, MTPDeviceWithMultipleStorageObjects
) {
511 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages
,
513 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages
,
517 TEST_F(StorageMonitorWinTest
, DriveNumberToFilePath
) {
518 EXPECT_EQ(L
"A:\\", VolumeMountWatcherWin::DriveNumberToFilePath(0).value());
519 EXPECT_EQ(L
"Y:\\", VolumeMountWatcherWin::DriveNumberToFilePath(24).value());
520 EXPECT_EQ(L
"", VolumeMountWatcherWin::DriveNumberToFilePath(-1).value());
521 EXPECT_EQ(L
"", VolumeMountWatcherWin::DriveNumberToFilePath(199).value());
524 // Given a MTP storage persistent id, GetMTPStorageInfo() should fetch the
525 // device interface path and local storage object identifier.
526 TEST_F(StorageMonitorWinTest
, GetMTPStorageInfoFromDeviceId
) {
527 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
, true);
528 PortableDeviceWatcherWin::StorageObjects storage_objects
=
529 TestPortableDeviceWatcherWin::GetDeviceStorageObjects(
530 TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
);
531 for (PortableDeviceWatcherWin::StorageObjects::const_iterator it
=
532 storage_objects
.begin();
533 it
!= storage_objects
.end(); ++it
) {
534 base::string16 pnp_device_id
;
535 base::string16 storage_object_id
;
536 ASSERT_TRUE(GetMTPStorageInfo(it
->object_persistent_id
, &pnp_device_id
,
537 &storage_object_id
));
538 base::string16
expected(
539 TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
);
540 EXPECT_EQ(expected
, pnp_device_id
);
541 EXPECT_EQ(it
->object_persistent_id
,
542 TestPortableDeviceWatcherWin::GetMTPStorageUniqueId(
543 pnp_device_id
, storage_object_id
));
545 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
, false);
548 } // namespace storage_monitor