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_
);
100 volume_mount_watcher_
->ShutdownWorkerPool();
102 // Windows storage monitor must be destroyed on the same thread
107 void StorageMonitorWinTest::PreAttachDevices() {
109 volume_mount_watcher_
= new TestVolumeMountWatcherWin
;
110 volume_mount_watcher_
->SetAttachedDevicesFake();
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
) {
118 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceRemovable(*it
, &removable
));
120 expect_attach_calls
++;
123 monitor_
.reset(new TestStorageMonitorWin(volume_mount_watcher_
,
124 new TestPortableDeviceWatcherWin
));
126 monitor_
->AddObserver(&observer_
);
129 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
131 // This dance is because attachment bounces through a couple of
132 // closures, which need to be executed to finish the process.
134 volume_mount_watcher_
->FlushWorkerPoolForTesting();
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());
145 void StorageMonitorWinTest::RunUntilIdle() {
146 volume_mount_watcher_
->FlushWorkerPoolForTesting();
147 base::RunLoop().RunUntilIdle();
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;
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
;
163 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceRemovable(
164 VolumeMountWatcherWin::DriveNumberToFilePath(*it
), &removable
));
166 expect_attach_calls
++;
168 monitor_
->InjectDeviceChange(DBT_DEVICEARRIVAL
,
169 reinterpret_cast<DWORD
>(&volume_broadcast
));
172 volume_mount_watcher_
->FlushWorkerPoolForTesting();
175 EXPECT_EQ(expect_attach_calls
, observer_
.attach_calls());
176 EXPECT_EQ(0, observer_
.detach_calls());
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;
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
;
193 ASSERT_TRUE(volume_mount_watcher_
->GetDeviceInfo(
194 VolumeMountWatcherWin::DriveNumberToFilePath(*it
), &info
));
195 if (StorageInfo::IsRemovableDevice(info
.device_id()))
196 ++expect_detach_calls
;
198 monitor_
->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE
,
199 reinterpret_cast<DWORD
>(&volume_broadcast
));
201 EXPECT_EQ(pre_attach_calls
, observer_
.attach_calls());
202 EXPECT_EQ(expect_detach_calls
, observer_
.detach_calls());
205 void StorageMonitorWinTest::DoMTPDeviceTest(const base::string16
& pnp_device_id
,
207 GUID guidDevInterface
= GUID_NULL
;
208 HRESULT hr
= CLSIDFromString(kWPDDevInterfaceGUID
, &guidDevInterface
);
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(),
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
;
233 base::string16 location
;
234 TestPortableDeviceWatcherWin::GetMTPStorageDetails(pnp_device_id
, *it
,
235 &location
, &unique_id
,
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
++;
243 monitor_
->InjectDeviceChange(
244 test_attach
? DBT_DEVICEARRIVAL
: DBT_DEVICEREMOVECOMPLETE
,
245 reinterpret_cast<DWORD
>(dev_interface_broadcast
.get()));
248 EXPECT_EQ(expect_attach_calls
, observer_
.attach_calls());
249 EXPECT_EQ(expect_detach_calls
, observer_
.detach_calls());
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
,
261 TEST_F(StorageMonitorWinTest
, RandomMessage
) {
262 monitor_
->InjectDeviceChange(DBT_DEVICEQUERYREMOVE
, NULL
);
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
);
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}\\",
280 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info
.storage_label());
282 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(
283 base::FilePath(ASCIIToUTF16("G:\\")), &info
));
284 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
285 base::FilePath(ASCIIToUTF16("F:\\")), &info
));
287 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(
288 base::FilePath(ASCIIToUTF16("F:\\subdir")), &info1
));
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());
297 TEST_F(StorageMonitorWinTest
, PathMountDevices
) {
299 int init_storages
= monitor_
->GetAllAvailableStorages().size();
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);
311 EXPECT_EQ(init_storages
+ 3, monitor_
->GetAllAvailableStorages().size());
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));
337 TEST_F(StorageMonitorWinTest
, DevicesAttachedHighBoundary
) {
338 DeviceIndices device_indices
;
339 device_indices
.push_back(25);
341 DoMassStorageDeviceAttachedTest(device_indices
);
344 TEST_F(StorageMonitorWinTest
, DevicesAttachedLowBoundary
) {
345 DeviceIndices device_indices
;
346 device_indices
.push_back(0);
348 DoMassStorageDeviceAttachedTest(device_indices
);
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);
358 DoMassStorageDeviceAttachedTest(device_indices
);
361 TEST_F(StorageMonitorWinTest
, DevicesDetached
) {
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);
370 DoMassStorageDevicesDetachedTest(device_indices
);
373 TEST_F(StorageMonitorWinTest
, DevicesDetachedHighBoundary
) {
376 DeviceIndices device_indices
;
377 device_indices
.push_back(25);
379 DoMassStorageDevicesDetachedTest(device_indices
);
382 TEST_F(StorageMonitorWinTest
, DevicesDetachedLowBoundary
) {
385 DeviceIndices device_indices
;
386 device_indices
.push_back(0);
388 DoMassStorageDevicesDetachedTest(device_indices
);
391 TEST_F(StorageMonitorWinTest
, DevicesDetachedAdjacentBits
) {
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);
400 DoMassStorageDevicesDetachedTest(device_indices
);
403 TEST_F(StorageMonitorWinTest
, DuplicateAttachCheckSuppressed
) {
404 // Make sure the original C: mount notification makes it all the
407 volume_mount_watcher_
->FlushWorkerPoolForTesting();
410 volume_mount_watcher_
->BlockDeviceCheckForTesting();
411 base::FilePath kAttachedDevicePath
=
412 VolumeMountWatcherWin::DriveNumberToFilePath(8); // I:
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
));
422 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
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
));
430 EXPECT_EQ(0u, volume_mount_watcher_
->devices_checked().size());
431 volume_mount_watcher_
->ReleaseDeviceCheck();
433 volume_mount_watcher_
->ReleaseDeviceCheck();
435 // Now let all attach notifications finish running. We'll only get one
436 // finish-attach call.
437 volume_mount_watcher_
->FlushWorkerPoolForTesting();
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]);
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();
452 ASSERT_EQ(2u, checked_devices
.size());
453 EXPECT_EQ(kAttachedDevicePath
, checked_devices
[0]);
454 EXPECT_EQ(kAttachedDevicePath
, checked_devices
[1]);
457 TEST_F(StorageMonitorWinTest
, DeviceInfoForPath
) {
460 StorageInfo device_info
;
462 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(base::FilePath(L
"COM1:\\"),
465 // An unconnected removable device.
466 EXPECT_FALSE(monitor_
->GetStorageInfoForPath(base::FilePath(L
"E:\\"),
469 // A connected removable device.
470 base::FilePath
removable_device(L
"F:\\");
471 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(removable_device
, &device_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());
482 base::FilePath
fixed_device(L
"N:\\");
483 EXPECT_TRUE(monitor_
->GetStorageInfoForPath(fixed_device
, &device_info
));
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());
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);
499 // When a MTP storage device with invalid storage label and id is
500 // attached/detached, there should not be any device attach/detach
502 TEST_F(StorageMonitorWinTest
, MTPDeviceWithInvalidInfo
) {
503 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo
,
505 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo
,
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
,
514 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages
,
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());
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
));
546 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo
, false);
549 } // namespace storage_monitor