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.
6 #include "base/message_loop/message_loop.h"
7 #include "chromeos/dbus/dbus_thread_manager.h"
8 #include "chromeos/dbus/fake_cros_disks_client.h"
9 #include "chromeos/disks/disk_mount_manager.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 using chromeos::disks::DiskMountManager
;
14 using chromeos::CrosDisksClient
;
15 using chromeos::DBusThreadManager
;
16 using chromeos::FakeCrosDisksClient
;
19 using testing::InSequence
;
23 // Holds information needed to create a DiskMountManager::Disk instance.
25 const char* source_path
;
26 const char* mount_path
;
27 const char* system_path
;
28 const char* file_path
;
29 const char* device_label
;
30 const char* drive_label
;
31 const char* vendor_id
;
32 const char* vendor_name
;
33 const char* product_id
;
34 const char* product_name
;
36 const char* system_path_prefix
;
37 chromeos::DeviceType device_type
;
43 bool on_removable_device
;
47 // Holds information to create a DiskMOuntManager::MountPointInfo instance.
48 struct TestMountPointInfo
{
49 const char* source_path
;
50 const char* mount_path
;
51 chromeos::MountType mount_type
;
52 chromeos::disks::MountCondition mount_condition
;
55 // List of disks held in DiskMountManager at the begining of the test.
56 const TestDiskInfo kTestDisks
[] = {
58 "/device/source_path",
60 "/device/prefix/system_path",
62 "/device/device_label",
63 "/device/drive_label",
65 "/device/vendor_name",
67 "/device/product_name",
70 chromeos::DEVICE_TYPE_USB
,
71 1073741824, // size in bytes
73 false, // is read only
75 false, // is on boot device
76 true, // is on removable device
81 // List of mount points held in DiskMountManager at the begining of the test.
82 const TestMountPointInfo kTestMountPoints
[] = {
84 "/archive/source_path",
85 "/archive/mount_path",
86 chromeos::MOUNT_TYPE_ARCHIVE
,
87 chromeos::disks::MOUNT_CONDITION_NONE
90 "/device/source_path",
92 chromeos::MOUNT_TYPE_DEVICE
,
93 chromeos::disks::MOUNT_CONDITION_NONE
97 // Mocks DiskMountManager observer.
98 class MockDiskMountManagerObserver
: public DiskMountManager::Observer
{
100 virtual ~MockDiskMountManagerObserver() {}
102 MOCK_METHOD2(OnDiskEvent
, void(DiskMountManager::DiskEvent event
,
103 const DiskMountManager::Disk
* disk
));
104 MOCK_METHOD2(OnDeviceEvent
, void(DiskMountManager::DeviceEvent event
,
105 const std::string
& device_path
));
106 MOCK_METHOD3(OnMountEvent
,
107 void(DiskMountManager::MountEvent event
,
108 chromeos::MountError error_code
,
109 const DiskMountManager::MountPointInfo
& mount_point
));
110 MOCK_METHOD3(OnFormatEvent
,
111 void(DiskMountManager::FormatEvent event
,
112 chromeos::FormatError error_code
,
113 const std::string
& device_path
));
116 class DiskMountManagerTest
: public testing::Test
{
118 DiskMountManagerTest() {}
119 ~DiskMountManagerTest() override
{}
121 // Sets up test dbus tread manager and disks mount manager.
122 // Initializes disk mount manager disks and mount points.
123 // Adds a test observer to the disk mount manager.
124 void SetUp() override
{
125 fake_cros_disks_client_
= new FakeCrosDisksClient
;
126 DBusThreadManager::GetSetterForTesting()->SetCrosDisksClient(
127 scoped_ptr
<CrosDisksClient
>(fake_cros_disks_client_
));
129 DiskMountManager::Initialize();
131 InitDisksAndMountPoints();
133 DiskMountManager::GetInstance()->AddObserver(&observer_
);
136 // Shuts down dbus thread manager and disk moutn manager used in the test.
137 void TearDown() override
{
138 DiskMountManager::GetInstance()->RemoveObserver(&observer_
);
139 DiskMountManager::Shutdown();
140 DBusThreadManager::Shutdown();
144 // Checks if disk mount manager contains a mount point with specified moutn
146 bool HasMountPoint(const std::string
& mount_path
) {
147 const DiskMountManager::MountPointMap
& mount_points
=
148 DiskMountManager::GetInstance()->mount_points();
149 return mount_points
.find(mount_path
) != mount_points
.end();
153 // Adds a new disk to the disk mount manager.
154 void AddTestDisk(const TestDiskInfo
& disk
) {
155 EXPECT_TRUE(DiskMountManager::GetInstance()->AddDiskForTest(
156 new DiskMountManager::Disk(disk
.source_path
,
167 disk
.system_path_prefix
,
174 disk
.on_removable_device
,
178 // Adds a new mount point to the disk mount manager.
179 // If the moutn point is a device mount point, disk with its source path
180 // should already be added to the disk mount manager.
181 void AddTestMountPoint(const TestMountPointInfo
& mount_point
) {
182 EXPECT_TRUE(DiskMountManager::GetInstance()->AddMountPointForTest(
183 DiskMountManager::MountPointInfo(mount_point
.source_path
,
184 mount_point
.mount_path
,
185 mount_point
.mount_type
,
186 mount_point
.mount_condition
)));
189 // Adds disks and mount points to disk mount manager.
190 void InitDisksAndMountPoints() {
191 // Disks should be added first (when adding device mount points it is
192 // expected that the corresponding disk is already added).
193 for (size_t i
= 0; i
< arraysize(kTestDisks
); i
++)
194 AddTestDisk(kTestDisks
[i
]);
196 for (size_t i
= 0; i
< arraysize(kTestMountPoints
); i
++)
197 AddTestMountPoint(kTestMountPoints
[i
]);
201 chromeos::FakeCrosDisksClient
* fake_cros_disks_client_
;
202 MockDiskMountManagerObserver observer_
;
203 base::MessageLoopForUI message_loop_
;
206 // Tests that the observer gets notified on attempt to format non existent mount
208 TEST_F(DiskMountManagerTest
, Format_NotMounted
) {
209 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
210 chromeos::FORMAT_ERROR_UNKNOWN
,
211 "/mount/non_existent"))
213 DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
216 // Tests that it is not possible to format archive mount point.
217 TEST_F(DiskMountManagerTest
, Format_Archive
) {
218 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
219 chromeos::FORMAT_ERROR_UNKNOWN
,
220 "/archive/source_path"))
223 DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
226 // Tests that format fails if the device cannot be unmounted.
227 TEST_F(DiskMountManagerTest
, Format_FailToUnmount
) {
228 // Before formatting mounted device, the device should be unmounted.
229 // In this test unmount will fail, and there should be no attempt to
230 // format the device.
232 // Set up expectations for observer mock.
233 // Observer should be notified that unmount attempt fails and format task
238 EXPECT_CALL(observer_
,
239 OnMountEvent(DiskMountManager::UNMOUNTING
,
240 chromeos::MOUNT_ERROR_INTERNAL
,
241 Field(&DiskMountManager::MountPointInfo::mount_path
,
242 "/device/mount_path")))
245 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
246 chromeos::FORMAT_ERROR_UNKNOWN
,
247 "/device/source_path"))
251 fake_cros_disks_client_
->MakeUnmountFail();
253 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
255 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
256 message_loop_
.RunUntilIdle();
258 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
259 EXPECT_EQ("/device/mount_path",
260 fake_cros_disks_client_
->last_unmount_device_path());
261 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
262 fake_cros_disks_client_
->last_unmount_options());
263 EXPECT_EQ(0, fake_cros_disks_client_
->format_call_count());
265 // The device mount should still be here.
266 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
269 // Tests that observer is notified when cros disks fails to start format
271 TEST_F(DiskMountManagerTest
, Format_FormatFailsToStart
) {
272 // Before formatting mounted device, the device should be unmounted.
273 // In this test, unmount will succeed, but call to Format method will
276 // Set up expectations for observer mock.
277 // Observer should be notified that the device was unmounted and format task
282 EXPECT_CALL(observer_
,
283 OnMountEvent(DiskMountManager::UNMOUNTING
,
284 chromeos::MOUNT_ERROR_NONE
,
285 Field(&DiskMountManager::MountPointInfo::mount_path
,
286 "/device/mount_path")))
289 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
290 chromeos::FORMAT_ERROR_UNKNOWN
,
291 "/device/source_path"))
295 fake_cros_disks_client_
->MakeFormatFail();
297 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
299 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
300 message_loop_
.RunUntilIdle();
302 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
303 EXPECT_EQ("/device/mount_path",
304 fake_cros_disks_client_
->last_unmount_device_path());
305 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
306 fake_cros_disks_client_
->last_unmount_options());
307 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
308 EXPECT_EQ("/device/source_path",
309 fake_cros_disks_client_
->last_format_device_path());
310 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
312 // The device mount should be gone.
313 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
316 // Tests the case where there are two format requests for the same device.
317 TEST_F(DiskMountManagerTest
, Format_ConcurrentFormatCalls
) {
318 // Only the first format request should be processed (the second unmount
319 // request fails because the device is already unmounted at that point).
320 // CrosDisksClient will report that the format process for the first request
321 // is successfully started.
323 // Set up expectations for observer mock.
324 // The observer should get a FORMAT_STARTED event for one format request and a
325 // FORMAT_COMPLETED with an error code for the other format request. The
326 // formatting will be started only for the first request.
327 // There should be only one UNMOUNTING event. The result of the second one
328 // should not be reported as the mount point will go away after the first
331 // Note that in this test the format completion signal will not be simulated,
332 // so the observer should not get FORMAT_COMPLETED signal.
336 EXPECT_CALL(observer_
,
337 OnMountEvent(DiskMountManager::UNMOUNTING
,
338 chromeos::MOUNT_ERROR_NONE
,
339 Field(&DiskMountManager::MountPointInfo::mount_path
,
340 "/device/mount_path")))
343 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
344 chromeos::FORMAT_ERROR_UNKNOWN
,
345 "/device/source_path"))
348 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
349 chromeos::FORMAT_ERROR_NONE
,
350 "/device/source_path"))
354 fake_cros_disks_client_
->set_unmount_listener(
355 base::Bind(&FakeCrosDisksClient::MakeUnmountFail
,
356 base::Unretained(fake_cros_disks_client_
)));
358 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
359 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
361 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
362 message_loop_
.RunUntilIdle();
364 EXPECT_EQ(2, fake_cros_disks_client_
->unmount_call_count());
365 EXPECT_EQ("/device/mount_path",
366 fake_cros_disks_client_
->last_unmount_device_path());
367 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
368 fake_cros_disks_client_
->last_unmount_options());
369 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
370 EXPECT_EQ("/device/source_path",
371 fake_cros_disks_client_
->last_format_device_path());
373 fake_cros_disks_client_
->last_format_filesystem());
375 // The device mount should be gone.
376 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
379 // Tests the case when the format process actually starts and fails.
380 TEST_F(DiskMountManagerTest
, Format_FormatFails
) {
381 // Both unmount and format device cals are successful in this test.
383 // Set up expectations for observer mock.
384 // The observer should get notified that the device was unmounted and that
385 // formatting has started.
386 // After the formatting starts, the test will simulate failing
387 // FORMAT_COMPLETED signal, so the observer should also be notified the
388 // formatting has failed (FORMAT_COMPLETED event).
392 EXPECT_CALL(observer_
,
393 OnMountEvent(DiskMountManager::UNMOUNTING
,
394 chromeos::MOUNT_ERROR_NONE
,
395 Field(&DiskMountManager::MountPointInfo::mount_path
,
396 "/device/mount_path")))
399 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
400 chromeos::FORMAT_ERROR_NONE
,
401 "/device/source_path"))
404 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
405 chromeos::FORMAT_ERROR_UNKNOWN
,
406 "/device/source_path"))
411 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
413 // Wait for Unmount and Format calls to end.
414 message_loop_
.RunUntilIdle();
416 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
417 EXPECT_EQ("/device/mount_path",
418 fake_cros_disks_client_
->last_unmount_device_path());
419 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
420 fake_cros_disks_client_
->last_unmount_options());
421 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
422 EXPECT_EQ("/device/source_path",
423 fake_cros_disks_client_
->last_format_device_path());
424 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
426 // The device should be unmounted by now.
427 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
429 // Send failing FORMAT_COMPLETED signal.
430 // The failure is marked by ! in fromt of the path (but this should change
432 fake_cros_disks_client_
->SendFormatCompletedEvent(
433 chromeos::FORMAT_ERROR_UNKNOWN
, "/device/source_path");
436 // Tests the case when formatting completes successfully.
437 TEST_F(DiskMountManagerTest
, Format_FormatSuccess
) {
438 // Set up cros disks client mocks.
439 // Both unmount and format device cals are successful in this test.
441 // Set up expectations for observer mock.
442 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
443 // events (all of them without an error set).
447 EXPECT_CALL(observer_
,
448 OnMountEvent(DiskMountManager::UNMOUNTING
,
449 chromeos::MOUNT_ERROR_NONE
,
450 Field(&DiskMountManager::MountPointInfo::mount_path
,
451 "/device/mount_path")))
454 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
455 chromeos::FORMAT_ERROR_NONE
,
456 "/device/source_path"))
459 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
460 chromeos::FORMAT_ERROR_NONE
,
461 "/device/source_path"))
466 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
468 // Wait for Unmount and Format calls to end.
469 message_loop_
.RunUntilIdle();
471 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
472 EXPECT_EQ("/device/mount_path",
473 fake_cros_disks_client_
->last_unmount_device_path());
474 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
475 fake_cros_disks_client_
->last_unmount_options());
476 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
477 EXPECT_EQ("/device/source_path",
478 fake_cros_disks_client_
->last_format_device_path());
479 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
481 // The device should be unmounted by now.
482 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
484 // Simulate cros_disks reporting success.
485 fake_cros_disks_client_
->SendFormatCompletedEvent(
486 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");
489 // Tests that it's possible to format the device twice in a row (this may not be
490 // true if the list of pending formats is not properly cleared).
491 TEST_F(DiskMountManagerTest
, Format_ConsecutiveFormatCalls
) {
492 // All unmount and format device cals are successful in this test.
493 // Each of the should be made twice (once for each formatting task).
495 // Set up expectations for observer mock.
496 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
497 // events (all of them without an error set) twice (once for each formatting
499 // Also, there should be a MOUNTING event when the device remounting is
501 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
502 chromeos::FORMAT_ERROR_NONE
,
503 "/device/source_path"))
506 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
507 chromeos::FORMAT_ERROR_NONE
,
508 "/device/source_path"))
511 EXPECT_CALL(observer_
,
512 OnMountEvent(DiskMountManager::UNMOUNTING
,
513 chromeos::MOUNT_ERROR_NONE
,
514 Field(&DiskMountManager::MountPointInfo::mount_path
,
515 "/device/mount_path")))
518 EXPECT_CALL(observer_
,
519 OnMountEvent(DiskMountManager::MOUNTING
,
520 chromeos::MOUNT_ERROR_NONE
,
521 Field(&DiskMountManager::MountPointInfo::mount_path
,
522 "/device/mount_path")))
526 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
528 // Wait for Unmount and Format calls to end.
529 message_loop_
.RunUntilIdle();
531 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
532 EXPECT_EQ("/device/mount_path",
533 fake_cros_disks_client_
->last_unmount_device_path());
534 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
535 fake_cros_disks_client_
->last_unmount_options());
536 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
537 EXPECT_EQ("/device/source_path",
538 fake_cros_disks_client_
->last_format_device_path());
539 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
541 // The device should be unmounted by now.
542 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
544 // Simulate cros_disks reporting success.
545 fake_cros_disks_client_
->SendFormatCompletedEvent(
546 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");
548 // Simulate the device remounting.
549 fake_cros_disks_client_
->SendMountCompletedEvent(
550 chromeos::MOUNT_ERROR_NONE
,
551 "/device/source_path",
552 chromeos::MOUNT_TYPE_DEVICE
,
553 "/device/mount_path");
555 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
557 // Try formatting again.
558 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
560 // Wait for Unmount and Format calls to end.
561 message_loop_
.RunUntilIdle();
563 EXPECT_EQ(2, fake_cros_disks_client_
->unmount_call_count());
564 EXPECT_EQ("/device/mount_path",
565 fake_cros_disks_client_
->last_unmount_device_path());
566 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
567 fake_cros_disks_client_
->last_unmount_options());
568 EXPECT_EQ(2, fake_cros_disks_client_
->format_call_count());
569 EXPECT_EQ("/device/source_path",
570 fake_cros_disks_client_
->last_format_device_path());
571 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
573 // Simulate cros_disks reporting success.
574 fake_cros_disks_client_
->SendFormatCompletedEvent(
575 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");