Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chromeos / disks / disk_mount_manager_unittest.cc
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.
4
5 #include "base/bind.h"
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"
12
13 using chromeos::disks::DiskMountManager;
14 using chromeos::CrosDisksClient;
15 using chromeos::DBusThreadManager;
16 using chromeos::FakeCrosDisksClient;
17 using testing::_;
18 using testing::Field;
19 using testing::InSequence;
20
21 namespace {
22
23 // Holds information needed to create a DiskMountManager::Disk instance.
24 struct TestDiskInfo {
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;
35   const char* fs_uuid;
36   const char* system_path_prefix;
37   chromeos::DeviceType device_type;
38   uint64 size_in_bytes;
39   bool is_parent;
40   bool is_read_only;
41   bool has_media;
42   bool on_boot_device;
43   bool on_removable_device;
44   bool is_hidden;
45 };
46
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;
53 };
54
55 // List of disks held in DiskMountManager at the begining of the test.
56 const TestDiskInfo kTestDisks[] = {
57   {
58     "/device/source_path",
59     "/device/mount_path",
60     "/device/prefix/system_path",
61     "/device/file_path",
62     "/device/device_label",
63     "/device/drive_label",
64     "/device/vendor_id",
65     "/device/vendor_name",
66     "/device/product_id",
67     "/device/product_name",
68     "/device/fs_uuid",
69     "/device/prefix",
70     chromeos::DEVICE_TYPE_USB,
71     1073741824,  // size in bytes
72     false,  // is parent
73     false,  // is read only
74     true,  // has media
75     false,  // is on boot device
76     true,  // is on removable device
77     false  // is hidden
78   },
79 };
80
81 // List of mount points  held in DiskMountManager at the begining of the test.
82 const TestMountPointInfo kTestMountPoints[] = {
83   {
84     "/archive/source_path",
85     "/archive/mount_path",
86     chromeos::MOUNT_TYPE_ARCHIVE,
87     chromeos::disks::MOUNT_CONDITION_NONE
88   },
89   {
90     "/device/source_path",
91     "/device/mount_path",
92     chromeos::MOUNT_TYPE_DEVICE,
93     chromeos::disks::MOUNT_CONDITION_NONE
94   },
95 };
96
97 // Mocks DiskMountManager observer.
98 class MockDiskMountManagerObserver : public DiskMountManager::Observer {
99  public:
100   virtual ~MockDiskMountManagerObserver() {}
101
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));
114 };
115
116 class DiskMountManagerTest : public testing::Test {
117  public:
118   DiskMountManagerTest() {}
119   virtual ~DiskMountManagerTest() {}
120
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   virtual void SetUp() {
125     fake_cros_disks_client_ = new FakeCrosDisksClient;
126     DBusThreadManager::GetSetterForTesting()->SetCrosDisksClient(
127         scoped_ptr<CrosDisksClient>(fake_cros_disks_client_));
128
129     DiskMountManager::Initialize();
130
131     InitDisksAndMountPoints();
132
133     DiskMountManager::GetInstance()->AddObserver(&observer_);
134   }
135
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();
141   }
142
143  protected:
144   // Checks if disk mount manager contains a mount point with specified moutn
145   // path.
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();
150   }
151
152  private:
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,
157                                    disk.mount_path,
158                                    disk.system_path,
159                                    disk.file_path,
160                                    disk.device_label,
161                                    disk.drive_label,
162                                    disk.vendor_id,
163                                    disk.vendor_name,
164                                    disk.product_id,
165                                    disk.product_name,
166                                    disk.fs_uuid,
167                                    disk.system_path_prefix,
168                                    disk.device_type,
169                                    disk.size_in_bytes,
170                                    disk.is_parent,
171                                    disk.is_read_only,
172                                    disk.has_media,
173                                    disk.on_boot_device,
174                                    disk.on_removable_device,
175                                    disk.is_hidden)));
176   }
177
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)));
187   }
188
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]);
195
196     for (size_t i = 0; i < arraysize(kTestMountPoints); i++)
197       AddTestMountPoint(kTestMountPoints[i]);
198   }
199
200  protected:
201   chromeos::FakeCrosDisksClient* fake_cros_disks_client_;
202   MockDiskMountManagerObserver observer_;
203   base::MessageLoopForUI message_loop_;
204 };
205
206 // Tests that the observer gets notified on attempt to format non existent mount
207 // point.
208 TEST_F(DiskMountManagerTest, Format_NotMounted) {
209   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
210                                        chromeos::FORMAT_ERROR_UNKNOWN,
211                                        "/mount/non_existent"))
212       .Times(1);
213   DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
214 }
215
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"))
221       .Times(1);
222
223   DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
224 }
225
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.
231
232   // Set up expectations for observer mock.
233   // Observer should be notified that unmount attempt fails and format task
234   // failed to start.
235   {
236     InSequence s;
237
238     EXPECT_CALL(observer_,
239         OnMountEvent(DiskMountManager::UNMOUNTING,
240                      chromeos::MOUNT_ERROR_INTERNAL,
241                      Field(&DiskMountManager::MountPointInfo::mount_path,
242                            "/device/mount_path")))
243         .Times(1);
244
245     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
246                                          chromeos::FORMAT_ERROR_UNKNOWN,
247                                          "/device/source_path"))
248         .Times(1);
249   }
250
251   fake_cros_disks_client_->MakeUnmountFail();
252   // Start test.
253   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
254
255   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
256   message_loop_.RunUntilIdle();
257
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());
264
265   // The device mount should still be here.
266   EXPECT_TRUE(HasMountPoint("/device/mount_path"));
267 }
268
269 // Tests that observer is notified when cros disks fails to start format
270 // process.
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
274   // fail.
275
276   // Set up expectations for observer mock.
277   // Observer should be notified that the device was unmounted and format task
278   // failed to start.
279   {
280     InSequence s;
281
282     EXPECT_CALL(observer_,
283         OnMountEvent(DiskMountManager::UNMOUNTING,
284                      chromeos::MOUNT_ERROR_NONE,
285                      Field(&DiskMountManager::MountPointInfo::mount_path,
286                            "/device/mount_path")))
287         .Times(1);
288
289     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
290                                          chromeos::FORMAT_ERROR_UNKNOWN,
291                                          "/device/source_path"))
292         .Times(1);
293   }
294
295   fake_cros_disks_client_->MakeFormatFail();
296   // Start the test.
297   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
298
299   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
300   message_loop_.RunUntilIdle();
301
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());
311
312   // The device mount should be gone.
313   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
314 }
315
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.
322
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
329   // request.
330   //
331   // Note that in this test the format completion signal will not be simulated,
332   // so the observer should not get FORMAT_COMPLETED signal.
333   {
334     InSequence s;
335
336     EXPECT_CALL(observer_,
337         OnMountEvent(DiskMountManager::UNMOUNTING,
338                      chromeos::MOUNT_ERROR_NONE,
339                      Field(&DiskMountManager::MountPointInfo::mount_path,
340                            "/device/mount_path")))
341         .Times(1);
342
343     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
344                                          chromeos::FORMAT_ERROR_UNKNOWN,
345                                          "/device/source_path"))
346         .Times(1);
347
348     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
349                                          chromeos::FORMAT_ERROR_NONE,
350                                          "/device/source_path"))
351         .Times(1);
352   }
353
354   fake_cros_disks_client_->set_unmount_listener(
355       base::Bind(&FakeCrosDisksClient::MakeUnmountFail,
356                  base::Unretained(fake_cros_disks_client_)));
357   // Start the test.
358   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
359   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
360
361   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
362   message_loop_.RunUntilIdle();
363
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());
372   EXPECT_EQ("vfat",
373             fake_cros_disks_client_->last_format_filesystem());
374
375   // The device mount should be gone.
376   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
377 }
378
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.
382
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).
389   {
390     InSequence s;
391
392     EXPECT_CALL(observer_,
393         OnMountEvent(DiskMountManager::UNMOUNTING,
394                      chromeos::MOUNT_ERROR_NONE,
395                      Field(&DiskMountManager::MountPointInfo::mount_path,
396                            "/device/mount_path")))
397         .Times(1);
398
399     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
400                                          chromeos::FORMAT_ERROR_NONE,
401                                          "/device/source_path"))
402         .Times(1);
403
404     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
405                                          chromeos::FORMAT_ERROR_UNKNOWN,
406                                          "/device/source_path"))
407         .Times(1);
408   }
409
410   // Start the test.
411   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
412
413   // Wait for Unmount and Format calls to end.
414   message_loop_.RunUntilIdle();
415
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());
425
426   // The device should be unmounted by now.
427   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
428
429   // Send failing FORMAT_COMPLETED signal.
430   // The failure is marked by ! in fromt of the path (but this should change
431   // soon).
432   fake_cros_disks_client_->SendFormatCompletedEvent(
433       chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path");
434 }
435
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.
440
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).
444   {
445     InSequence s;
446
447     EXPECT_CALL(observer_,
448         OnMountEvent(DiskMountManager::UNMOUNTING,
449                      chromeos::MOUNT_ERROR_NONE,
450                      Field(&DiskMountManager::MountPointInfo::mount_path,
451                            "/device/mount_path")))
452         .Times(1);
453
454     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
455                                          chromeos::FORMAT_ERROR_NONE,
456                                          "/device/source_path"))
457         .Times(1);
458
459     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
460                                          chromeos::FORMAT_ERROR_NONE,
461                                          "/device/source_path"))
462         .Times(1);
463   }
464
465   // Start the test.
466   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
467
468   // Wait for Unmount and Format calls to end.
469   message_loop_.RunUntilIdle();
470
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());
480
481   // The device should be unmounted by now.
482   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
483
484   // Simulate cros_disks reporting success.
485   fake_cros_disks_client_->SendFormatCompletedEvent(
486       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
487 }
488
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).
494
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
498   // task).
499   // Also, there should be a MOUNTING event when the device remounting is
500   // simulated.
501   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
502                                        chromeos::FORMAT_ERROR_NONE,
503                                        "/device/source_path"))
504       .Times(2);
505
506   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
507                                        chromeos::FORMAT_ERROR_NONE,
508                                        "/device/source_path"))
509       .Times(2);
510
511   EXPECT_CALL(observer_,
512       OnMountEvent(DiskMountManager::UNMOUNTING,
513                    chromeos::MOUNT_ERROR_NONE,
514                    Field(&DiskMountManager::MountPointInfo::mount_path,
515                          "/device/mount_path")))
516       .Times(2);
517
518   EXPECT_CALL(observer_,
519       OnMountEvent(DiskMountManager::MOUNTING,
520                    chromeos::MOUNT_ERROR_NONE,
521                    Field(&DiskMountManager::MountPointInfo::mount_path,
522                          "/device/mount_path")))
523       .Times(1);
524
525   // Start the test.
526   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
527
528   // Wait for Unmount and Format calls to end.
529   message_loop_.RunUntilIdle();
530
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());
540
541   // The device should be unmounted by now.
542   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
543
544   // Simulate cros_disks reporting success.
545   fake_cros_disks_client_->SendFormatCompletedEvent(
546       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
547
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");
554
555   EXPECT_TRUE(HasMountPoint("/device/mount_path"));
556
557   // Try formatting again.
558   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
559
560   // Wait for Unmount and Format calls to end.
561   message_loop_.RunUntilIdle();
562
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());
572
573   // Simulate cros_disks reporting success.
574   fake_cros_disks_client_->SendFormatCompletedEvent(
575       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
576 }
577
578 }  // namespace