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 DBusThreadManager::InitializeForTesting(fake_thread_manager);
127 fake_cros_disks_client_ = fake_thread_manager->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 virtual void TearDown() {
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,
177 // Adds a new mount point to the disk mount manager.
178 // If the moutn point is a device mount point, disk with its source path
179 // should already be added to the disk mount manager.
180 void AddTestMountPoint(const TestMountPointInfo& mount_point) {
181 EXPECT_TRUE(DiskMountManager::GetInstance()->AddMountPointForTest(
182 DiskMountManager::MountPointInfo(mount_point.source_path,
183 mount_point.mount_path,
184 mount_point.mount_type,
185 mount_point.mount_condition)));
188 // Adds disks and mount points to disk mount manager.
189 void InitDisksAndMountPoints() {
190 // Disks should be added first (when adding device mount points it is
191 // expected that the corresponding disk is already added).
192 for (size_t i = 0; i < arraysize(kTestDisks); i++)
193 AddTestDisk(kTestDisks[i]);
195 for (size_t i = 0; i < arraysize(kTestMountPoints); i++)
196 AddTestMountPoint(kTestMountPoints[i]);
200 chromeos::FakeCrosDisksClient* fake_cros_disks_client_;
201 MockDiskMountManagerObserver observer_;
202 base::MessageLoopForUI message_loop_;
205 // Tests that the observer gets notified on attempt to format non existent mount
207 TEST_F(DiskMountManagerTest, Format_NotMounted) {
208 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
209 chromeos::FORMAT_ERROR_UNKNOWN,
210 "/mount/non_existent"))
212 DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
215 // Tests that it is not possible to format archive mount point.
216 TEST_F(DiskMountManagerTest, Format_Archive) {
217 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
218 chromeos::FORMAT_ERROR_UNKNOWN,
219 "/archive/source_path"))
222 DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
225 // Tests that format fails if the device cannot be unmounted.
226 TEST_F(DiskMountManagerTest, Format_FailToUnmount) {
227 // Before formatting mounted device, the device should be unmounted.
228 // In this test unmount will fail, and there should be no attempt to
229 // format the device.
231 // Set up expectations for observer mock.
232 // Observer should be notified that unmount attempt fails and format task
237 EXPECT_CALL(observer_,
238 OnMountEvent(DiskMountManager::UNMOUNTING,
239 chromeos::MOUNT_ERROR_INTERNAL,
240 Field(&DiskMountManager::MountPointInfo::mount_path,
241 "/device/mount_path")))
244 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
245 chromeos::FORMAT_ERROR_UNKNOWN,
246 "/device/source_path"))
250 fake_cros_disks_client_->MakeUnmountFail();
252 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
254 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
255 message_loop_.RunUntilIdle();
257 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
258 EXPECT_EQ("/device/mount_path",
259 fake_cros_disks_client_->last_unmount_device_path());
260 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
261 fake_cros_disks_client_->last_unmount_options());
262 EXPECT_EQ(0, fake_cros_disks_client_->format_device_call_count());
264 // The device mount should still be here.
265 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
268 // Tests that observer is notified when cros disks fails to start format
270 TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) {
271 // Before formatting mounted device, the device should be unmounted.
272 // In this test, unmount will succeed, but call to FormatDevice method will
275 // Set up expectations for observer mock.
276 // Observer should be notified that the device was unmounted and format task
281 EXPECT_CALL(observer_,
282 OnMountEvent(DiskMountManager::UNMOUNTING,
283 chromeos::MOUNT_ERROR_NONE,
284 Field(&DiskMountManager::MountPointInfo::mount_path,
285 "/device/mount_path")))
288 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
289 chromeos::FORMAT_ERROR_UNKNOWN,
290 "/device/source_path"))
294 fake_cros_disks_client_->MakeFormatDeviceFail();
296 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
298 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
299 message_loop_.RunUntilIdle();
301 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
302 EXPECT_EQ("/device/mount_path",
303 fake_cros_disks_client_->last_unmount_device_path());
304 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
305 fake_cros_disks_client_->last_unmount_options());
306 EXPECT_EQ(1, fake_cros_disks_client_->format_device_call_count());
307 EXPECT_EQ("/device/source_path",
308 fake_cros_disks_client_->last_format_device_device_path());
310 fake_cros_disks_client_->last_format_device_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 two FORMAT_STARTED events, one for each format
325 // request, but with different error codes (the formatting will be started
326 // 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_STARTED,
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_device_call_count());
370 EXPECT_EQ("/device/source_path",
371 fake_cros_disks_client_->last_format_device_device_path());
373 fake_cros_disks_client_->last_format_device_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 successfull 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 // FORMATTING_FINISHED 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 FormatDevice 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_device_call_count());
422 EXPECT_EQ("/device/source_path",
423 fake_cros_disks_client_->last_format_device_device_path());
425 fake_cros_disks_client_->last_format_device_filesystem());
427 // The device should be unmounted by now.
428 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
430 // Send failing FORMATTING_FINISHED signal.
431 // The failure is marked by ! in fromt of the path (but this should change
433 fake_cros_disks_client_->SendMountEvent(
434 chromeos::CROS_DISKS_FORMATTING_FINISHED, "!/device/source_path");
437 // Tests the same case as Format_FormatFails, but the FORMATTING_FINISHED event
438 // is sent with file_path of the formatted device (instead of its device path).
439 TEST_F(DiskMountManagerTest, Format_FormatFailsAndReturnFilePath) {
440 // Set up expectations for observer mock.
444 EXPECT_CALL(observer_,
445 OnMountEvent(DiskMountManager::UNMOUNTING,
446 chromeos::MOUNT_ERROR_NONE,
447 Field(&DiskMountManager::MountPointInfo::mount_path,
448 "/device/mount_path")))
451 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
452 chromeos::FORMAT_ERROR_NONE,
453 "/device/source_path"))
456 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
457 chromeos::FORMAT_ERROR_UNKNOWN,
458 "/device/source_path"))
463 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
465 // Wait for Unmount and FormatDevice calls to end.
466 message_loop_.RunUntilIdle();
468 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
469 EXPECT_EQ("/device/mount_path",
470 fake_cros_disks_client_->last_unmount_device_path());
471 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
472 fake_cros_disks_client_->last_unmount_options());
473 EXPECT_EQ(1, fake_cros_disks_client_->format_device_call_count());
474 EXPECT_EQ("/device/source_path",
475 fake_cros_disks_client_->last_format_device_device_path());
477 fake_cros_disks_client_->last_format_device_filesystem());
479 // The device should be unmounted by now.
480 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
482 // Send failing FORMATTING_FINISHED signal with the device's file path.
483 fake_cros_disks_client_->SendMountEvent(
484 chromeos::CROS_DISKS_FORMATTING_FINISHED, "!/device/file_path");
487 // Tests the case when formatting completes successfully.
488 TEST_F(DiskMountManagerTest, Format_FormatSuccess) {
489 // Set up cros disks client mocks.
490 // Both unmount and format device cals are successfull in this test.
492 // Set up expectations for observer mock.
493 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
494 // events (all of them without an error set).
498 EXPECT_CALL(observer_,
499 OnMountEvent(DiskMountManager::UNMOUNTING,
500 chromeos::MOUNT_ERROR_NONE,
501 Field(&DiskMountManager::MountPointInfo::mount_path,
502 "/device/mount_path")))
505 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
506 chromeos::FORMAT_ERROR_NONE,
507 "/device/source_path"))
510 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
511 chromeos::FORMAT_ERROR_NONE,
512 "/device/source_path"))
517 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
519 // Wait for Unmount and FormatDevice calls to end.
520 message_loop_.RunUntilIdle();
522 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
523 EXPECT_EQ("/device/mount_path",
524 fake_cros_disks_client_->last_unmount_device_path());
525 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
526 fake_cros_disks_client_->last_unmount_options());
527 EXPECT_EQ(1, fake_cros_disks_client_->format_device_call_count());
528 EXPECT_EQ("/device/source_path",
529 fake_cros_disks_client_->last_format_device_device_path());
531 fake_cros_disks_client_->last_format_device_filesystem());
533 // The device should be unmounted by now.
534 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
536 // Simulate cros_disks reporting success.
537 fake_cros_disks_client_->SendMountEvent(
538 chromeos::CROS_DISKS_FORMATTING_FINISHED, "/device/source_path");
541 // Tests that it's possible to format the device twice in a row (this may not be
542 // true if the list of pending formats is not properly cleared).
543 TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) {
544 // All unmount and format device cals are successfull in this test.
545 // Each of the should be made twice (once for each formatting task).
547 // Set up expectations for observer mock.
548 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
549 // events (all of them without an error set) twice (once for each formatting
551 // Also, there should be a MOUNTING event when the device remounting is
553 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
554 chromeos::FORMAT_ERROR_NONE,
555 "/device/source_path"))
558 EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
559 chromeos::FORMAT_ERROR_NONE,
560 "/device/source_path"))
563 EXPECT_CALL(observer_,
564 OnMountEvent(DiskMountManager::UNMOUNTING,
565 chromeos::MOUNT_ERROR_NONE,
566 Field(&DiskMountManager::MountPointInfo::mount_path,
567 "/device/mount_path")))
570 EXPECT_CALL(observer_,
571 OnMountEvent(DiskMountManager::MOUNTING,
572 chromeos::MOUNT_ERROR_NONE,
573 Field(&DiskMountManager::MountPointInfo::mount_path,
574 "/device/mount_path")))
578 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
580 // Wait for Unmount and FormatDevice calls to end.
581 message_loop_.RunUntilIdle();
583 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
584 EXPECT_EQ("/device/mount_path",
585 fake_cros_disks_client_->last_unmount_device_path());
586 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
587 fake_cros_disks_client_->last_unmount_options());
588 EXPECT_EQ(1, fake_cros_disks_client_->format_device_call_count());
589 EXPECT_EQ("/device/source_path",
590 fake_cros_disks_client_->last_format_device_device_path());
592 fake_cros_disks_client_->last_format_device_filesystem());
594 // The device should be unmounted by now.
595 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
597 // Simulate cros_disks reporting success.
598 fake_cros_disks_client_->SendMountEvent(
599 chromeos::CROS_DISKS_FORMATTING_FINISHED, "/device/source_path");
601 // Simulate the device remounting.
602 fake_cros_disks_client_->SendMountCompletedEvent(
603 chromeos::MOUNT_ERROR_NONE,
604 "/device/source_path",
605 chromeos::MOUNT_TYPE_DEVICE,
606 "/device/mount_path");
608 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
610 // Try formatting again.
611 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
613 // Wait for Unmount and FormatDevice calls to end.
614 message_loop_.RunUntilIdle();
616 EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
617 EXPECT_EQ("/device/mount_path",
618 fake_cros_disks_client_->last_unmount_device_path());
619 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
620 fake_cros_disks_client_->last_unmount_options());
621 EXPECT_EQ(2, fake_cros_disks_client_->format_device_call_count());
622 EXPECT_EQ("/device/source_path",
623 fake_cros_disks_client_->last_format_device_device_path());
625 fake_cros_disks_client_->last_format_device_filesystem());
627 // Simulate cros_disks reporting success.
628 fake_cros_disks_client_->SendMountEvent(
629 chromeos::CROS_DISKS_FORMATTING_FINISHED, "/device/source_path");