Upstream version 9.38.198.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/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"
12
13 using chromeos::disks::DiskMountManager;
14 using chromeos::CrosDisksClient;
15 using chromeos::DBusThreadManager;
16 using chromeos::FakeCrosDisksClient;
17 using chromeos::FakeDBusThreadManager;
18 using testing::_;
19 using testing::Field;
20 using testing::InSequence;
21
22 namespace {
23
24 // Holds information needed to create a DiskMountManager::Disk instance.
25 struct TestDiskInfo {
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;
36   const char* fs_uuid;
37   const char* system_path_prefix;
38   chromeos::DeviceType device_type;
39   uint64 size_in_bytes;
40   bool is_parent;
41   bool is_read_only;
42   bool has_media;
43   bool on_boot_device;
44   bool on_removable_device;
45   bool is_hidden;
46 };
47
48 // Holds information to create a DiskMOuntManager::MountPointInfo instance.
49 struct TestMountPointInfo {
50   const char* source_path;
51   const char* mount_path;
52   chromeos::MountType mount_type;
53   chromeos::disks::MountCondition mount_condition;
54 };
55
56 // List of disks held in DiskMountManager at the begining of the test.
57 const TestDiskInfo kTestDisks[] = {
58   {
59     "/device/source_path",
60     "/device/mount_path",
61     "/device/prefix/system_path",
62     "/device/file_path",
63     "/device/device_label",
64     "/device/drive_label",
65     "/device/vendor_id",
66     "/device/vendor_name",
67     "/device/product_id",
68     "/device/product_name",
69     "/device/fs_uuid",
70     "/device/prefix",
71     chromeos::DEVICE_TYPE_USB,
72     1073741824,  // size in bytes
73     false,  // is parent
74     false,  // is read only
75     true,  // has media
76     false,  // is on boot device
77     true,  // is on removable device
78     false  // is hidden
79   },
80 };
81
82 // List of mount points  held in DiskMountManager at the begining of the test.
83 const TestMountPointInfo kTestMountPoints[] = {
84   {
85     "/archive/source_path",
86     "/archive/mount_path",
87     chromeos::MOUNT_TYPE_ARCHIVE,
88     chromeos::disks::MOUNT_CONDITION_NONE
89   },
90   {
91     "/device/source_path",
92     "/device/mount_path",
93     chromeos::MOUNT_TYPE_DEVICE,
94     chromeos::disks::MOUNT_CONDITION_NONE
95   },
96 };
97
98 // Mocks DiskMountManager observer.
99 class MockDiskMountManagerObserver : public DiskMountManager::Observer {
100  public:
101   virtual ~MockDiskMountManagerObserver() {}
102
103   MOCK_METHOD2(OnDiskEvent, void(DiskMountManager::DiskEvent event,
104                                  const DiskMountManager::Disk* disk));
105   MOCK_METHOD2(OnDeviceEvent, void(DiskMountManager::DeviceEvent event,
106                                    const std::string& device_path));
107   MOCK_METHOD3(OnMountEvent,
108       void(DiskMountManager::MountEvent event,
109            chromeos::MountError error_code,
110            const DiskMountManager::MountPointInfo& mount_point));
111   MOCK_METHOD3(OnFormatEvent,
112       void(DiskMountManager::FormatEvent event,
113            chromeos::FormatError error_code,
114            const std::string& device_path));
115 };
116
117 class DiskMountManagerTest : public testing::Test {
118  public:
119   DiskMountManagerTest() {}
120   virtual ~DiskMountManagerTest() {}
121
122   // Sets up test dbus tread manager and disks mount manager.
123   // Initializes disk mount manager disks and mount points.
124   // Adds a test observer to the disk mount manager.
125   virtual void SetUp() {
126     FakeDBusThreadManager* fake_thread_manager = new FakeDBusThreadManager();
127     fake_cros_disks_client_ = new FakeCrosDisksClient;
128     fake_thread_manager->SetCrosDisksClient(
129         scoped_ptr<CrosDisksClient>(fake_cros_disks_client_));
130
131     DBusThreadManager::InitializeForTesting(fake_thread_manager);
132
133     DiskMountManager::Initialize();
134
135     InitDisksAndMountPoints();
136
137     DiskMountManager::GetInstance()->AddObserver(&observer_);
138   }
139
140   // Shuts down dbus thread manager and disk moutn manager used in the test.
141   virtual void TearDown() {
142     DiskMountManager::GetInstance()->RemoveObserver(&observer_);
143     DiskMountManager::Shutdown();
144     DBusThreadManager::Shutdown();
145   }
146
147  protected:
148   // Checks if disk mount manager contains a mount point with specified moutn
149   // path.
150   bool HasMountPoint(const std::string& mount_path) {
151     const DiskMountManager::MountPointMap& mount_points =
152         DiskMountManager::GetInstance()->mount_points();
153     return mount_points.find(mount_path) != mount_points.end();
154   }
155
156  private:
157   // Adds a new disk to the disk mount manager.
158   void AddTestDisk(const TestDiskInfo& disk) {
159     EXPECT_TRUE(DiskMountManager::GetInstance()->AddDiskForTest(
160         new DiskMountManager::Disk(disk.source_path,
161                                    disk.mount_path,
162                                    disk.system_path,
163                                    disk.file_path,
164                                    disk.device_label,
165                                    disk.drive_label,
166                                    disk.vendor_id,
167                                    disk.vendor_name,
168                                    disk.product_id,
169                                    disk.product_name,
170                                    disk.fs_uuid,
171                                    disk.system_path_prefix,
172                                    disk.device_type,
173                                    disk.size_in_bytes,
174                                    disk.is_parent,
175                                    disk.is_read_only,
176                                    disk.has_media,
177                                    disk.on_boot_device,
178                                    disk.on_removable_device,
179                                    disk.is_hidden)));
180   }
181
182   // Adds a new mount point to the disk mount manager.
183   // If the moutn point is a device mount point, disk with its source path
184   // should already be added to the disk mount manager.
185   void AddTestMountPoint(const TestMountPointInfo& mount_point) {
186     EXPECT_TRUE(DiskMountManager::GetInstance()->AddMountPointForTest(
187         DiskMountManager::MountPointInfo(mount_point.source_path,
188                                          mount_point.mount_path,
189                                          mount_point.mount_type,
190                                          mount_point.mount_condition)));
191   }
192
193   // Adds disks and mount points to disk mount manager.
194   void InitDisksAndMountPoints() {
195     // Disks should be  added first (when adding device mount points it is
196     // expected that the corresponding disk is already added).
197     for (size_t i = 0; i < arraysize(kTestDisks); i++)
198       AddTestDisk(kTestDisks[i]);
199
200     for (size_t i = 0; i < arraysize(kTestMountPoints); i++)
201       AddTestMountPoint(kTestMountPoints[i]);
202   }
203
204  protected:
205   chromeos::FakeCrosDisksClient* fake_cros_disks_client_;
206   MockDiskMountManagerObserver observer_;
207   base::MessageLoopForUI message_loop_;
208 };
209
210 // Tests that the observer gets notified on attempt to format non existent mount
211 // point.
212 TEST_F(DiskMountManagerTest, Format_NotMounted) {
213   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
214                                        chromeos::FORMAT_ERROR_UNKNOWN,
215                                        "/mount/non_existent"))
216       .Times(1);
217   DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
218 }
219
220 // Tests that it is not possible to format archive mount point.
221 TEST_F(DiskMountManagerTest, Format_Archive) {
222   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
223                                        chromeos::FORMAT_ERROR_UNKNOWN,
224                                        "/archive/source_path"))
225       .Times(1);
226
227   DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
228 }
229
230 // Tests that format fails if the device cannot be unmounted.
231 TEST_F(DiskMountManagerTest, Format_FailToUnmount) {
232   // Before formatting mounted device, the device should be unmounted.
233   // In this test unmount will fail, and there should be no attempt to
234   // format the device.
235
236   // Set up expectations for observer mock.
237   // Observer should be notified that unmount attempt fails and format task
238   // failed to start.
239   {
240     InSequence s;
241
242     EXPECT_CALL(observer_,
243         OnMountEvent(DiskMountManager::UNMOUNTING,
244                      chromeos::MOUNT_ERROR_INTERNAL,
245                      Field(&DiskMountManager::MountPointInfo::mount_path,
246                            "/device/mount_path")))
247         .Times(1);
248
249     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
250                                          chromeos::FORMAT_ERROR_UNKNOWN,
251                                          "/device/source_path"))
252         .Times(1);
253   }
254
255   fake_cros_disks_client_->MakeUnmountFail();
256   // Start test.
257   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
258
259   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
260   message_loop_.RunUntilIdle();
261
262   EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
263   EXPECT_EQ("/device/mount_path",
264             fake_cros_disks_client_->last_unmount_device_path());
265   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
266             fake_cros_disks_client_->last_unmount_options());
267   EXPECT_EQ(0, fake_cros_disks_client_->format_call_count());
268
269   // The device mount should still be here.
270   EXPECT_TRUE(HasMountPoint("/device/mount_path"));
271 }
272
273 // Tests that observer is notified when cros disks fails to start format
274 // process.
275 TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) {
276   // Before formatting mounted device, the device should be unmounted.
277   // In this test, unmount will succeed, but call to Format method will
278   // fail.
279
280   // Set up expectations for observer mock.
281   // Observer should be notified that the device was unmounted and format task
282   // failed to start.
283   {
284     InSequence s;
285
286     EXPECT_CALL(observer_,
287         OnMountEvent(DiskMountManager::UNMOUNTING,
288                      chromeos::MOUNT_ERROR_NONE,
289                      Field(&DiskMountManager::MountPointInfo::mount_path,
290                            "/device/mount_path")))
291         .Times(1);
292
293     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
294                                          chromeos::FORMAT_ERROR_UNKNOWN,
295                                          "/device/source_path"))
296         .Times(1);
297   }
298
299   fake_cros_disks_client_->MakeFormatFail();
300   // Start the test.
301   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
302
303   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
304   message_loop_.RunUntilIdle();
305
306   EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
307   EXPECT_EQ("/device/mount_path",
308             fake_cros_disks_client_->last_unmount_device_path());
309   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
310             fake_cros_disks_client_->last_unmount_options());
311   EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
312   EXPECT_EQ("/device/source_path",
313             fake_cros_disks_client_->last_format_device_path());
314   EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
315
316   // The device mount should be gone.
317   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
318 }
319
320 // Tests the case where there are two format requests for the same device.
321 TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) {
322   // Only the first format request should be processed (the second unmount
323   // request fails because the device is already unmounted at that point).
324   // CrosDisksClient will report that the format process for the first request
325   // is successfully started.
326
327   // Set up expectations for observer mock.
328   // The observer should get a FORMAT_STARTED event for one format request and a
329   // FORMAT_COMPLETED with an error code for the other format request. The
330   // formatting will be started only for the first request.
331   // There should be only one UNMOUNTING event. The result of the second one
332   // should not be reported as the mount point will go away after the first
333   // request.
334   //
335   // Note that in this test the format completion signal will not be simulated,
336   // so the observer should not get FORMAT_COMPLETED signal.
337   {
338     InSequence s;
339
340     EXPECT_CALL(observer_,
341         OnMountEvent(DiskMountManager::UNMOUNTING,
342                      chromeos::MOUNT_ERROR_NONE,
343                      Field(&DiskMountManager::MountPointInfo::mount_path,
344                            "/device/mount_path")))
345         .Times(1);
346
347     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
348                                          chromeos::FORMAT_ERROR_UNKNOWN,
349                                          "/device/source_path"))
350         .Times(1);
351
352     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
353                                          chromeos::FORMAT_ERROR_NONE,
354                                          "/device/source_path"))
355         .Times(1);
356   }
357
358   fake_cros_disks_client_->set_unmount_listener(
359       base::Bind(&FakeCrosDisksClient::MakeUnmountFail,
360                  base::Unretained(fake_cros_disks_client_)));
361   // Start the test.
362   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
363   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
364
365   // Cros disks will respond asynchronoulsy, so let's drain the message loop.
366   message_loop_.RunUntilIdle();
367
368   EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
369   EXPECT_EQ("/device/mount_path",
370             fake_cros_disks_client_->last_unmount_device_path());
371   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
372             fake_cros_disks_client_->last_unmount_options());
373   EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
374   EXPECT_EQ("/device/source_path",
375             fake_cros_disks_client_->last_format_device_path());
376   EXPECT_EQ("vfat",
377             fake_cros_disks_client_->last_format_filesystem());
378
379   // The device mount should be gone.
380   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
381 }
382
383 // Tests the case when the format process actually starts and fails.
384 TEST_F(DiskMountManagerTest, Format_FormatFails) {
385   // Both unmount and format device cals are successful in this test.
386
387   // Set up expectations for observer mock.
388   // The observer should get notified that the device was unmounted and that
389   // formatting has started.
390   // After the formatting starts, the test will simulate failing
391   // FORMAT_COMPLETED signal, so the observer should also be notified the
392   // formatting has failed (FORMAT_COMPLETED event).
393   {
394     InSequence s;
395
396     EXPECT_CALL(observer_,
397         OnMountEvent(DiskMountManager::UNMOUNTING,
398                      chromeos::MOUNT_ERROR_NONE,
399                      Field(&DiskMountManager::MountPointInfo::mount_path,
400                            "/device/mount_path")))
401         .Times(1);
402
403     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
404                                          chromeos::FORMAT_ERROR_NONE,
405                                          "/device/source_path"))
406         .Times(1);
407
408     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
409                                          chromeos::FORMAT_ERROR_UNKNOWN,
410                                          "/device/source_path"))
411         .Times(1);
412   }
413
414   // Start the test.
415   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
416
417   // Wait for Unmount and Format calls to end.
418   message_loop_.RunUntilIdle();
419
420   EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
421   EXPECT_EQ("/device/mount_path",
422             fake_cros_disks_client_->last_unmount_device_path());
423   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
424             fake_cros_disks_client_->last_unmount_options());
425   EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
426   EXPECT_EQ("/device/source_path",
427             fake_cros_disks_client_->last_format_device_path());
428   EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
429
430   // The device should be unmounted by now.
431   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
432
433   // Send failing FORMAT_COMPLETED signal.
434   // The failure is marked by ! in fromt of the path (but this should change
435   // soon).
436   fake_cros_disks_client_->SendFormatCompletedEvent(
437       chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path");
438 }
439
440 // Tests the case when formatting completes successfully.
441 TEST_F(DiskMountManagerTest, Format_FormatSuccess) {
442   // Set up cros disks client mocks.
443   // Both unmount and format device cals are successful in this test.
444
445   // Set up expectations for observer mock.
446   // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
447   // events (all of them without an error set).
448   {
449     InSequence s;
450
451     EXPECT_CALL(observer_,
452         OnMountEvent(DiskMountManager::UNMOUNTING,
453                      chromeos::MOUNT_ERROR_NONE,
454                      Field(&DiskMountManager::MountPointInfo::mount_path,
455                            "/device/mount_path")))
456         .Times(1);
457
458     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
459                                          chromeos::FORMAT_ERROR_NONE,
460                                          "/device/source_path"))
461         .Times(1);
462
463     EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
464                                          chromeos::FORMAT_ERROR_NONE,
465                                          "/device/source_path"))
466         .Times(1);
467   }
468
469   // Start the test.
470   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
471
472   // Wait for Unmount and Format calls to end.
473   message_loop_.RunUntilIdle();
474
475   EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
476   EXPECT_EQ("/device/mount_path",
477             fake_cros_disks_client_->last_unmount_device_path());
478   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
479             fake_cros_disks_client_->last_unmount_options());
480   EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
481   EXPECT_EQ("/device/source_path",
482             fake_cros_disks_client_->last_format_device_path());
483   EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
484
485   // The device should be unmounted by now.
486   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
487
488   // Simulate cros_disks reporting success.
489   fake_cros_disks_client_->SendFormatCompletedEvent(
490       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
491 }
492
493 // Tests that it's possible to format the device twice in a row (this may not be
494 // true if the list of pending formats is not properly cleared).
495 TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) {
496   // All unmount and format device cals are successful in this test.
497   // Each of the should be made twice (once for each formatting task).
498
499   // Set up expectations for observer mock.
500   // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
501   // events (all of them without an error set) twice (once for each formatting
502   // task).
503   // Also, there should be a MOUNTING event when the device remounting is
504   // simulated.
505   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
506                                        chromeos::FORMAT_ERROR_NONE,
507                                        "/device/source_path"))
508       .Times(2);
509
510   EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
511                                        chromeos::FORMAT_ERROR_NONE,
512                                        "/device/source_path"))
513       .Times(2);
514
515   EXPECT_CALL(observer_,
516       OnMountEvent(DiskMountManager::UNMOUNTING,
517                    chromeos::MOUNT_ERROR_NONE,
518                    Field(&DiskMountManager::MountPointInfo::mount_path,
519                          "/device/mount_path")))
520       .Times(2);
521
522   EXPECT_CALL(observer_,
523       OnMountEvent(DiskMountManager::MOUNTING,
524                    chromeos::MOUNT_ERROR_NONE,
525                    Field(&DiskMountManager::MountPointInfo::mount_path,
526                          "/device/mount_path")))
527       .Times(1);
528
529   // Start the test.
530   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
531
532   // Wait for Unmount and Format calls to end.
533   message_loop_.RunUntilIdle();
534
535   EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
536   EXPECT_EQ("/device/mount_path",
537             fake_cros_disks_client_->last_unmount_device_path());
538   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
539             fake_cros_disks_client_->last_unmount_options());
540   EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
541   EXPECT_EQ("/device/source_path",
542             fake_cros_disks_client_->last_format_device_path());
543   EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
544
545   // The device should be unmounted by now.
546   EXPECT_FALSE(HasMountPoint("/device/mount_path"));
547
548   // Simulate cros_disks reporting success.
549   fake_cros_disks_client_->SendFormatCompletedEvent(
550       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
551
552   // Simulate the device remounting.
553   fake_cros_disks_client_->SendMountCompletedEvent(
554       chromeos::MOUNT_ERROR_NONE,
555       "/device/source_path",
556       chromeos::MOUNT_TYPE_DEVICE,
557       "/device/mount_path");
558
559   EXPECT_TRUE(HasMountPoint("/device/mount_path"));
560
561   // Try formatting again.
562   DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
563
564   // Wait for Unmount and Format calls to end.
565   message_loop_.RunUntilIdle();
566
567   EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
568   EXPECT_EQ("/device/mount_path",
569             fake_cros_disks_client_->last_unmount_device_path());
570   EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
571             fake_cros_disks_client_->last_unmount_options());
572   EXPECT_EQ(2, fake_cros_disks_client_->format_call_count());
573   EXPECT_EQ("/device/source_path",
574             fake_cros_disks_client_->last_format_device_path());
575   EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
576
577   // Simulate cros_disks reporting success.
578   fake_cros_disks_client_->SendFormatCompletedEvent(
579       chromeos::FORMAT_ERROR_NONE, "/device/source_path");
580 }
581
582 }  // namespace