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/fake_cros_disks_client.h"
8 #include "chromeos/dbus/fake_dbus_thread_manager.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
;
17 using chromeos::FakeDBusThreadManager
;
20 using testing::InSequence
;
24 // Holds information needed to create a DiskMountManager::Disk instance.
26 const char* source_path
;
27 const char* mount_path
;
28 const char* system_path
;
29 const char* file_path
;
30 const char* device_label
;
31 const char* drive_label
;
32 const char* vendor_id
;
33 const char* vendor_name
;
34 const char* product_id
;
35 const char* product_name
;
37 const char* system_path_prefix
;
38 chromeos::DeviceType device_type
;
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
80 // List of mount points held in DiskMountManager at the begining of the test.
81 const TestMountPointInfo kTestMountPoints
[] = {
83 "/archive/source_path",
84 "/archive/mount_path",
85 chromeos::MOUNT_TYPE_ARCHIVE
,
86 chromeos::disks::MOUNT_CONDITION_NONE
89 "/device/source_path",
91 chromeos::MOUNT_TYPE_DEVICE
,
92 chromeos::disks::MOUNT_CONDITION_NONE
96 // Mocks DiskMountManager observer.
97 class MockDiskMountManagerObserver
: public DiskMountManager::Observer
{
99 virtual ~MockDiskMountManagerObserver() {}
101 MOCK_METHOD2(OnDiskEvent
, void(DiskMountManager::DiskEvent event
,
102 const DiskMountManager::Disk
* disk
));
103 MOCK_METHOD2(OnDeviceEvent
, void(DiskMountManager::DeviceEvent event
,
104 const std::string
& device_path
));
105 MOCK_METHOD3(OnMountEvent
,
106 void(DiskMountManager::MountEvent event
,
107 chromeos::MountError error_code
,
108 const DiskMountManager::MountPointInfo
& mount_point
));
109 MOCK_METHOD3(OnFormatEvent
,
110 void(DiskMountManager::FormatEvent event
,
111 chromeos::FormatError error_code
,
112 const std::string
& device_path
));
115 class DiskMountManagerTest
: public testing::Test
{
117 DiskMountManagerTest() {}
118 virtual ~DiskMountManagerTest() {}
120 // Sets up test dbus tread manager and disks mount manager.
121 // Initializes disk mount manager disks and mount points.
122 // Adds a test observer to the disk mount manager.
123 virtual void SetUp() {
124 FakeDBusThreadManager
* fake_thread_manager
= new FakeDBusThreadManager();
125 fake_cros_disks_client_
= new FakeCrosDisksClient
;
126 fake_thread_manager
->SetCrosDisksClient(
127 scoped_ptr
<CrosDisksClient
>(fake_cros_disks_client_
));
129 DBusThreadManager::InitializeForTesting(fake_thread_manager
);
131 DiskMountManager::Initialize();
133 InitDisksAndMountPoints();
135 DiskMountManager::GetInstance()->AddObserver(&observer_
);
138 // Shuts down dbus thread manager and disk moutn manager used in the test.
139 virtual void TearDown() {
140 DiskMountManager::GetInstance()->RemoveObserver(&observer_
);
141 DiskMountManager::Shutdown();
142 DBusThreadManager::Shutdown();
146 // Checks if disk mount manager contains a mount point with specified moutn
148 bool HasMountPoint(const std::string
& mount_path
) {
149 const DiskMountManager::MountPointMap
& mount_points
=
150 DiskMountManager::GetInstance()->mount_points();
151 return mount_points
.find(mount_path
) != mount_points
.end();
155 // Adds a new disk to the disk mount manager.
156 void AddTestDisk(const TestDiskInfo
& disk
) {
157 EXPECT_TRUE(DiskMountManager::GetInstance()->AddDiskForTest(
158 new DiskMountManager::Disk(disk
.source_path
,
169 disk
.system_path_prefix
,
179 // Adds a new mount point to the disk mount manager.
180 // If the moutn point is a device mount point, disk with its source path
181 // should already be added to the disk mount manager.
182 void AddTestMountPoint(const TestMountPointInfo
& mount_point
) {
183 EXPECT_TRUE(DiskMountManager::GetInstance()->AddMountPointForTest(
184 DiskMountManager::MountPointInfo(mount_point
.source_path
,
185 mount_point
.mount_path
,
186 mount_point
.mount_type
,
187 mount_point
.mount_condition
)));
190 // Adds disks and mount points to disk mount manager.
191 void InitDisksAndMountPoints() {
192 // Disks should be added first (when adding device mount points it is
193 // expected that the corresponding disk is already added).
194 for (size_t i
= 0; i
< arraysize(kTestDisks
); i
++)
195 AddTestDisk(kTestDisks
[i
]);
197 for (size_t i
= 0; i
< arraysize(kTestMountPoints
); i
++)
198 AddTestMountPoint(kTestMountPoints
[i
]);
202 chromeos::FakeCrosDisksClient
* fake_cros_disks_client_
;
203 MockDiskMountManagerObserver observer_
;
204 base::MessageLoopForUI message_loop_
;
207 // Tests that the observer gets notified on attempt to format non existent mount
209 TEST_F(DiskMountManagerTest
, Format_NotMounted
) {
210 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
211 chromeos::FORMAT_ERROR_UNKNOWN
,
212 "/mount/non_existent"))
214 DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
217 // Tests that it is not possible to format archive mount point.
218 TEST_F(DiskMountManagerTest
, Format_Archive
) {
219 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
220 chromeos::FORMAT_ERROR_UNKNOWN
,
221 "/archive/source_path"))
224 DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
227 // Tests that format fails if the device cannot be unmounted.
228 TEST_F(DiskMountManagerTest
, Format_FailToUnmount
) {
229 // Before formatting mounted device, the device should be unmounted.
230 // In this test unmount will fail, and there should be no attempt to
231 // format the device.
233 // Set up expectations for observer mock.
234 // Observer should be notified that unmount attempt fails and format task
239 EXPECT_CALL(observer_
,
240 OnMountEvent(DiskMountManager::UNMOUNTING
,
241 chromeos::MOUNT_ERROR_INTERNAL
,
242 Field(&DiskMountManager::MountPointInfo::mount_path
,
243 "/device/mount_path")))
246 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
247 chromeos::FORMAT_ERROR_UNKNOWN
,
248 "/device/source_path"))
252 fake_cros_disks_client_
->MakeUnmountFail();
254 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
256 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
257 message_loop_
.RunUntilIdle();
259 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
260 EXPECT_EQ("/device/mount_path",
261 fake_cros_disks_client_
->last_unmount_device_path());
262 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
263 fake_cros_disks_client_
->last_unmount_options());
264 EXPECT_EQ(0, fake_cros_disks_client_
->format_call_count());
266 // The device mount should still be here.
267 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
270 // Tests that observer is notified when cros disks fails to start format
272 TEST_F(DiskMountManagerTest
, Format_FormatFailsToStart
) {
273 // Before formatting mounted device, the device should be unmounted.
274 // In this test, unmount will succeed, but call to Format method will
277 // Set up expectations for observer mock.
278 // Observer should be notified that the device was unmounted and format task
283 EXPECT_CALL(observer_
,
284 OnMountEvent(DiskMountManager::UNMOUNTING
,
285 chromeos::MOUNT_ERROR_NONE
,
286 Field(&DiskMountManager::MountPointInfo::mount_path
,
287 "/device/mount_path")))
290 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
291 chromeos::FORMAT_ERROR_UNKNOWN
,
292 "/device/source_path"))
296 fake_cros_disks_client_
->MakeFormatFail();
298 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
300 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
301 message_loop_
.RunUntilIdle();
303 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
304 EXPECT_EQ("/device/mount_path",
305 fake_cros_disks_client_
->last_unmount_device_path());
306 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
307 fake_cros_disks_client_
->last_unmount_options());
308 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
309 EXPECT_EQ("/device/source_path",
310 fake_cros_disks_client_
->last_format_device_path());
311 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
313 // The device mount should be gone.
314 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
317 // Tests the case where there are two format requests for the same device.
318 TEST_F(DiskMountManagerTest
, Format_ConcurrentFormatCalls
) {
319 // Only the first format request should be processed (the second unmount
320 // request fails because the device is already unmounted at that point).
321 // CrosDisksClient will report that the format process for the first request
322 // is successfully started.
324 // Set up expectations for observer mock.
325 // The observer should get a FORMAT_STARTED event for one format request and a
326 // FORMAT_COMPLETED with an error code for the other format request. The
327 // formatting will be started only for the first request.
328 // There should be only one UNMOUNTING event. The result of the second one
329 // should not be reported as the mount point will go away after the first
332 // Note that in this test the format completion signal will not be simulated,
333 // so the observer should not get FORMAT_COMPLETED signal.
337 EXPECT_CALL(observer_
,
338 OnMountEvent(DiskMountManager::UNMOUNTING
,
339 chromeos::MOUNT_ERROR_NONE
,
340 Field(&DiskMountManager::MountPointInfo::mount_path
,
341 "/device/mount_path")))
344 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
345 chromeos::FORMAT_ERROR_UNKNOWN
,
346 "/device/source_path"))
349 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
350 chromeos::FORMAT_ERROR_NONE
,
351 "/device/source_path"))
355 fake_cros_disks_client_
->set_unmount_listener(
356 base::Bind(&FakeCrosDisksClient::MakeUnmountFail
,
357 base::Unretained(fake_cros_disks_client_
)));
359 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
360 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
362 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
363 message_loop_
.RunUntilIdle();
365 EXPECT_EQ(2, fake_cros_disks_client_
->unmount_call_count());
366 EXPECT_EQ("/device/mount_path",
367 fake_cros_disks_client_
->last_unmount_device_path());
368 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
369 fake_cros_disks_client_
->last_unmount_options());
370 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
371 EXPECT_EQ("/device/source_path",
372 fake_cros_disks_client_
->last_format_device_path());
374 fake_cros_disks_client_
->last_format_filesystem());
376 // The device mount should be gone.
377 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
380 // Tests the case when the format process actually starts and fails.
381 TEST_F(DiskMountManagerTest
, Format_FormatFails
) {
382 // Both unmount and format device cals are successful in this test.
384 // Set up expectations for observer mock.
385 // The observer should get notified that the device was unmounted and that
386 // formatting has started.
387 // After the formatting starts, the test will simulate failing
388 // FORMAT_COMPLETED signal, so the observer should also be notified the
389 // formatting has failed (FORMAT_COMPLETED event).
393 EXPECT_CALL(observer_
,
394 OnMountEvent(DiskMountManager::UNMOUNTING
,
395 chromeos::MOUNT_ERROR_NONE
,
396 Field(&DiskMountManager::MountPointInfo::mount_path
,
397 "/device/mount_path")))
400 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
401 chromeos::FORMAT_ERROR_NONE
,
402 "/device/source_path"))
405 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
406 chromeos::FORMAT_ERROR_UNKNOWN
,
407 "/device/source_path"))
412 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
414 // Wait for Unmount and Format calls to end.
415 message_loop_
.RunUntilIdle();
417 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
418 EXPECT_EQ("/device/mount_path",
419 fake_cros_disks_client_
->last_unmount_device_path());
420 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
421 fake_cros_disks_client_
->last_unmount_options());
422 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
423 EXPECT_EQ("/device/source_path",
424 fake_cros_disks_client_
->last_format_device_path());
425 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
427 // The device should be unmounted by now.
428 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
430 // Send failing FORMAT_COMPLETED signal.
431 // The failure is marked by ! in fromt of the path (but this should change
433 fake_cros_disks_client_
->SendFormatCompletedEvent(
434 chromeos::FORMAT_ERROR_UNKNOWN
, "/device/source_path");
437 // Tests the case when formatting completes successfully.
438 TEST_F(DiskMountManagerTest
, Format_FormatSuccess
) {
439 // Set up cros disks client mocks.
440 // Both unmount and format device cals are successful in this test.
442 // Set up expectations for observer mock.
443 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
444 // events (all of them without an error set).
448 EXPECT_CALL(observer_
,
449 OnMountEvent(DiskMountManager::UNMOUNTING
,
450 chromeos::MOUNT_ERROR_NONE
,
451 Field(&DiskMountManager::MountPointInfo::mount_path
,
452 "/device/mount_path")))
455 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
456 chromeos::FORMAT_ERROR_NONE
,
457 "/device/source_path"))
460 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
461 chromeos::FORMAT_ERROR_NONE
,
462 "/device/source_path"))
467 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
469 // Wait for Unmount and Format calls to end.
470 message_loop_
.RunUntilIdle();
472 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
473 EXPECT_EQ("/device/mount_path",
474 fake_cros_disks_client_
->last_unmount_device_path());
475 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
476 fake_cros_disks_client_
->last_unmount_options());
477 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
478 EXPECT_EQ("/device/source_path",
479 fake_cros_disks_client_
->last_format_device_path());
480 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
482 // The device should be unmounted by now.
483 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
485 // Simulate cros_disks reporting success.
486 fake_cros_disks_client_
->SendFormatCompletedEvent(
487 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");
490 // Tests that it's possible to format the device twice in a row (this may not be
491 // true if the list of pending formats is not properly cleared).
492 TEST_F(DiskMountManagerTest
, Format_ConsecutiveFormatCalls
) {
493 // All unmount and format device cals are successful in this test.
494 // Each of the should be made twice (once for each formatting task).
496 // Set up expectations for observer mock.
497 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
498 // events (all of them without an error set) twice (once for each formatting
500 // Also, there should be a MOUNTING event when the device remounting is
502 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED
,
503 chromeos::FORMAT_ERROR_NONE
,
504 "/device/source_path"))
507 EXPECT_CALL(observer_
, OnFormatEvent(DiskMountManager::FORMAT_STARTED
,
508 chromeos::FORMAT_ERROR_NONE
,
509 "/device/source_path"))
512 EXPECT_CALL(observer_
,
513 OnMountEvent(DiskMountManager::UNMOUNTING
,
514 chromeos::MOUNT_ERROR_NONE
,
515 Field(&DiskMountManager::MountPointInfo::mount_path
,
516 "/device/mount_path")))
519 EXPECT_CALL(observer_
,
520 OnMountEvent(DiskMountManager::MOUNTING
,
521 chromeos::MOUNT_ERROR_NONE
,
522 Field(&DiskMountManager::MountPointInfo::mount_path
,
523 "/device/mount_path")))
527 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
529 // Wait for Unmount and Format calls to end.
530 message_loop_
.RunUntilIdle();
532 EXPECT_EQ(1, fake_cros_disks_client_
->unmount_call_count());
533 EXPECT_EQ("/device/mount_path",
534 fake_cros_disks_client_
->last_unmount_device_path());
535 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
536 fake_cros_disks_client_
->last_unmount_options());
537 EXPECT_EQ(1, fake_cros_disks_client_
->format_call_count());
538 EXPECT_EQ("/device/source_path",
539 fake_cros_disks_client_
->last_format_device_path());
540 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
542 // The device should be unmounted by now.
543 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
545 // Simulate cros_disks reporting success.
546 fake_cros_disks_client_
->SendFormatCompletedEvent(
547 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");
549 // Simulate the device remounting.
550 fake_cros_disks_client_
->SendMountCompletedEvent(
551 chromeos::MOUNT_ERROR_NONE
,
552 "/device/source_path",
553 chromeos::MOUNT_TYPE_DEVICE
,
554 "/device/mount_path");
556 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
558 // Try formatting again.
559 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
561 // Wait for Unmount and Format calls to end.
562 message_loop_
.RunUntilIdle();
564 EXPECT_EQ(2, fake_cros_disks_client_
->unmount_call_count());
565 EXPECT_EQ("/device/mount_path",
566 fake_cros_disks_client_
->last_unmount_device_path());
567 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE
,
568 fake_cros_disks_client_
->last_unmount_options());
569 EXPECT_EQ(2, fake_cros_disks_client_
->format_call_count());
570 EXPECT_EQ("/device/source_path",
571 fake_cros_disks_client_
->last_format_device_path());
572 EXPECT_EQ("vfat", fake_cros_disks_client_
->last_format_filesystem());
574 // Simulate cros_disks reporting success.
575 fake_cros_disks_client_
->SendFormatCompletedEvent(
576 chromeos::FORMAT_ERROR_NONE
, "/device/source_path");