dd859d7dd9ba4d049f22bbd8722c88f34b50cb31
[platform/framework/web/crosswalk.git] / src / components / storage_monitor / storage_monitor_chromeos_unittest.cc
1 // Copyright 2014 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 "components/storage_monitor/storage_monitor_chromeos.h"
6
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chromeos/disks/mock_disk_mount_manager.h"
14 #include "components/storage_monitor/mock_removable_storage_observer.h"
15 #include "components/storage_monitor/removable_device_constants.h"
16 #include "components/storage_monitor/storage_info.h"
17 #include "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
18 #include "components/storage_monitor/test_storage_monitor.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace storage_monitor {
24
25 namespace {
26
27 using content::BrowserThread;
28 using chromeos::disks::DiskMountManager;
29 using testing::_;
30
31 const char kDevice1[] = "/dev/d1";
32 const char kDevice1Name[] = "d1";
33 const char kDevice2[] = "/dev/disk/d2";
34 const char kDevice2Name[] = "d2";
35 const char kEmptyDeviceLabel[] = "";
36 const char kMountPointA[] = "mnt_a";
37 const char kMountPointB[] = "mnt_b";
38 const char kSDCardDeviceName1[] = "8.6 MB Amy_SD";
39 const char kSDCardDeviceName2[] = "8.6 MB SD Card";
40 const char kSDCardMountPoint1[] = "media/removable/Amy_SD";
41 const char kSDCardMountPoint2[] = "media/removable/SD Card";
42 const char kProductName[] = "Z101";
43 const char kUniqueId1[] = "FFFF-FFFF";
44 const char kUniqueId2[] = "FFFF-FF0F";
45 const char kVendorName[] = "CompanyA";
46
47 uint64 kDevice1SizeInBytes = 113048;
48 uint64 kDevice2SizeInBytes = 212312;
49 uint64 kSDCardSizeInBytes = 9000000;
50
51 std::string GetDCIMDeviceId(const std::string& unique_id) {
52   return StorageInfo::MakeDeviceId(
53       StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
54       kFSUniqueIdPrefix + unique_id);
55 }
56
57 // A test version of StorageMonitorCros that exposes protected methods to tests.
58 class TestStorageMonitorCros : public StorageMonitorCros {
59  public:
60   TestStorageMonitorCros() {}
61
62   virtual ~TestStorageMonitorCros() {}
63
64   virtual void Init() OVERRIDE {
65     SetMediaTransferProtocolManagerForTest(
66         new TestMediaTransferProtocolManagerLinux());
67     StorageMonitorCros::Init();
68   }
69
70   virtual void OnMountEvent(DiskMountManager::MountEvent event,
71       chromeos::MountError error_code,
72       const DiskMountManager::MountPointInfo& mount_info) OVERRIDE {
73     StorageMonitorCros::OnMountEvent(event, error_code, mount_info);
74   }
75
76   virtual bool GetStorageInfoForPath(const base::FilePath& path,
77                                      StorageInfo* device_info) const OVERRIDE {
78     return StorageMonitorCros::GetStorageInfoForPath(path, device_info);
79   }
80   virtual void EjectDevice(
81       const std::string& device_id,
82       base::Callback<void(EjectStatus)> callback) OVERRIDE {
83     StorageMonitorCros::EjectDevice(device_id, callback);
84   }
85
86  private:
87   DISALLOW_COPY_AND_ASSIGN(TestStorageMonitorCros);
88 };
89
90 // Wrapper class to test StorageMonitorCros.
91 class StorageMonitorCrosTest : public testing::Test {
92  public:
93   StorageMonitorCrosTest();
94   virtual ~StorageMonitorCrosTest();
95
96   void EjectNotify(StorageMonitor::EjectStatus status);
97
98  protected:
99   // testing::Test:
100   virtual void SetUp() OVERRIDE;
101   virtual void TearDown() OVERRIDE;
102
103   void MountDevice(chromeos::MountError error_code,
104                    const DiskMountManager::MountPointInfo& mount_info,
105                    const std::string& unique_id,
106                    const std::string& device_label,
107                    const std::string& vendor_name,
108                    const std::string& product_name,
109                    chromeos::DeviceType device_type,
110                    uint64 device_size_in_bytes);
111
112   void UnmountDevice(chromeos::MountError error_code,
113                      const DiskMountManager::MountPointInfo& mount_info);
114
115   uint64 GetDeviceStorageSize(const std::string& device_location);
116
117   // Create a directory named |dir| relative to the test directory.
118   // Set |with_dcim_dir| to true if the created directory will have a "DCIM"
119   // subdirectory.
120   // Returns the full path to the created directory on success, or an empty
121   // path on failure.
122   base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir);
123
124   static void PostQuitToUIThread();
125   static void WaitForFileThread();
126
127   MockRemovableStorageObserver& observer() {
128     return *mock_storage_observer_;
129   }
130
131   TestStorageMonitorCros* monitor_;
132
133   // Owned by DiskMountManager.
134   chromeos::disks::MockDiskMountManager* disk_mount_manager_mock_;
135
136   StorageMonitor::EjectStatus status_;
137
138  private:
139   content::TestBrowserThreadBundle thread_bundle_;
140
141   // Temporary directory for created test data.
142   base::ScopedTempDir scoped_temp_dir_;
143
144   // Objects that talks with StorageMonitorCros.
145   scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
146
147   DISALLOW_COPY_AND_ASSIGN(StorageMonitorCrosTest);
148 };
149
150 StorageMonitorCrosTest::StorageMonitorCrosTest()
151     : monitor_(NULL),
152       disk_mount_manager_mock_(NULL),
153       status_(StorageMonitor::EJECT_FAILURE),
154       thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {
155 }
156
157 StorageMonitorCrosTest::~StorageMonitorCrosTest() {
158 }
159
160 void StorageMonitorCrosTest::SetUp() {
161   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
162   ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
163   disk_mount_manager_mock_ = new chromeos::disks::MockDiskMountManager();
164   DiskMountManager::InitializeForTesting(disk_mount_manager_mock_);
165   disk_mount_manager_mock_->SetupDefaultReplies();
166
167   mock_storage_observer_.reset(new MockRemovableStorageObserver);
168
169   // Initialize the test subject.
170   TestStorageMonitor::Destroy();
171   monitor_ = new TestStorageMonitorCros();
172   scoped_ptr<StorageMonitor> pass_monitor(monitor_);
173   StorageMonitor::SetStorageMonitorForTesting(pass_monitor.Pass());
174
175   monitor_->Init();
176   monitor_->AddObserver(mock_storage_observer_.get());
177 }
178
179 void StorageMonitorCrosTest::TearDown() {
180   monitor_->RemoveObserver(mock_storage_observer_.get());
181   monitor_ = NULL;
182
183   disk_mount_manager_mock_ = NULL;
184   DiskMountManager::Shutdown();
185   WaitForFileThread();
186 }
187
188 void StorageMonitorCrosTest::MountDevice(
189     chromeos::MountError error_code,
190     const DiskMountManager::MountPointInfo& mount_info,
191     const std::string& unique_id,
192     const std::string& device_label,
193     const std::string& vendor_name,
194     const std::string& product_name,
195     chromeos::DeviceType device_type,
196     uint64 device_size_in_bytes) {
197   if (error_code == chromeos::MOUNT_ERROR_NONE) {
198     disk_mount_manager_mock_->CreateDiskEntryForMountDevice(
199         mount_info, unique_id, device_label, vendor_name, product_name,
200         device_type, device_size_in_bytes);
201   }
202   monitor_->OnMountEvent(DiskMountManager::MOUNTING, error_code, mount_info);
203   WaitForFileThread();
204 }
205
206 void StorageMonitorCrosTest::UnmountDevice(
207     chromeos::MountError error_code,
208     const DiskMountManager::MountPointInfo& mount_info) {
209   monitor_->OnMountEvent(DiskMountManager::UNMOUNTING, error_code, mount_info);
210   if (error_code == chromeos::MOUNT_ERROR_NONE)
211     disk_mount_manager_mock_->RemoveDiskEntryForMountDevice(mount_info);
212   WaitForFileThread();
213 }
214
215 uint64 StorageMonitorCrosTest::GetDeviceStorageSize(
216     const std::string& device_location) {
217   StorageInfo info;
218   if (!monitor_->GetStorageInfoForPath(base::FilePath(device_location), &info))
219     return 0;
220
221   return info.total_size_in_bytes();
222 }
223
224 base::FilePath StorageMonitorCrosTest::CreateMountPoint(
225     const std::string& dir, bool with_dcim_dir) {
226   base::FilePath return_path(scoped_temp_dir_.path());
227   return_path = return_path.AppendASCII(dir);
228   base::FilePath path(return_path);
229   if (with_dcim_dir)
230     path = path.Append(kDCIMDirectoryName);
231   if (!base::CreateDirectory(path))
232     return base::FilePath();
233   return return_path;
234 }
235
236 // static
237 void StorageMonitorCrosTest::PostQuitToUIThread() {
238   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
239                           base::MessageLoop::QuitClosure());
240 }
241
242 // static
243 void StorageMonitorCrosTest::WaitForFileThread() {
244   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
245                           base::Bind(&PostQuitToUIThread));
246   base::MessageLoop::current()->Run();
247 }
248
249 void StorageMonitorCrosTest::EjectNotify(StorageMonitor::EjectStatus status) {
250   status_ = status;
251 }
252
253 // Simple test case where we attach and detach a media device.
254 TEST_F(StorageMonitorCrosTest, BasicAttachDetach) {
255   base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
256   ASSERT_FALSE(mount_path1.empty());
257   DiskMountManager::MountPointInfo mount_info(
258       kDevice1,
259       mount_path1.value(),
260       chromeos::MOUNT_TYPE_DEVICE,
261       chromeos::disks::MOUNT_CONDITION_NONE);
262   MountDevice(chromeos::MOUNT_ERROR_NONE,
263               mount_info,
264               kUniqueId1,
265               kDevice1Name,
266               kVendorName,
267               kProductName,
268               chromeos::DEVICE_TYPE_USB,
269               kDevice1SizeInBytes);
270   EXPECT_EQ(1, observer().attach_calls());
271   EXPECT_EQ(0, observer().detach_calls());
272   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
273             observer().last_attached().device_id());
274   EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
275
276   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info);
277   EXPECT_EQ(1, observer().attach_calls());
278   EXPECT_EQ(1, observer().detach_calls());
279   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
280             observer().last_detached().device_id());
281
282   base::FilePath mount_path2 = CreateMountPoint(kMountPointB, true);
283   ASSERT_FALSE(mount_path2.empty());
284   DiskMountManager::MountPointInfo mount_info2(
285       kDevice2,
286       mount_path2.value(),
287       chromeos::MOUNT_TYPE_DEVICE,
288       chromeos::disks::MOUNT_CONDITION_NONE);
289   MountDevice(chromeos::MOUNT_ERROR_NONE,
290               mount_info2,
291               kUniqueId2,
292               kDevice2Name,
293               kVendorName,
294               kProductName,
295               chromeos::DEVICE_TYPE_USB,
296               kDevice2SizeInBytes);
297   EXPECT_EQ(2, observer().attach_calls());
298   EXPECT_EQ(1, observer().detach_calls());
299   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
300             observer().last_attached().device_id());
301   EXPECT_EQ(mount_path2.value(), observer().last_attached().location());
302
303   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info2);
304   EXPECT_EQ(2, observer().attach_calls());
305   EXPECT_EQ(2, observer().detach_calls());
306   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
307             observer().last_detached().device_id());
308 }
309
310 // Removable mass storage devices with no dcim folder are also recognized.
311 TEST_F(StorageMonitorCrosTest, NoDCIM) {
312   testing::Sequence mock_sequence;
313   base::FilePath mount_path = CreateMountPoint(kMountPointA, false);
314   const std::string kUniqueId = "FFFF-FFFF";
315   ASSERT_FALSE(mount_path.empty());
316   DiskMountManager::MountPointInfo mount_info(
317       kDevice1,
318       mount_path.value(),
319       chromeos::MOUNT_TYPE_DEVICE,
320       chromeos::disks::MOUNT_CONDITION_NONE);
321   const std::string device_id = StorageInfo::MakeDeviceId(
322       StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM,
323       kFSUniqueIdPrefix + kUniqueId);
324   MountDevice(chromeos::MOUNT_ERROR_NONE,
325               mount_info,
326               kUniqueId,
327               kDevice1Name,
328               kVendorName,
329               kProductName,
330               chromeos::DEVICE_TYPE_USB,
331               kDevice1SizeInBytes);
332   EXPECT_EQ(1, observer().attach_calls());
333   EXPECT_EQ(0, observer().detach_calls());
334   EXPECT_EQ(device_id, observer().last_attached().device_id());
335   EXPECT_EQ(mount_path.value(), observer().last_attached().location());
336 }
337
338 // Non device mounts and mount errors are ignored.
339 TEST_F(StorageMonitorCrosTest, Ignore) {
340   testing::Sequence mock_sequence;
341   base::FilePath mount_path = CreateMountPoint(kMountPointA, true);
342   const std::string kUniqueId = "FFFF-FFFF";
343   ASSERT_FALSE(mount_path.empty());
344
345   // Mount error.
346   DiskMountManager::MountPointInfo mount_info(
347       kDevice1,
348       mount_path.value(),
349       chromeos::MOUNT_TYPE_DEVICE,
350       chromeos::disks::MOUNT_CONDITION_NONE);
351   MountDevice(chromeos::MOUNT_ERROR_UNKNOWN,
352               mount_info,
353               kUniqueId,
354               kDevice1Name,
355               kVendorName,
356               kProductName,
357               chromeos::DEVICE_TYPE_USB,
358               kDevice1SizeInBytes);
359   EXPECT_EQ(0, observer().attach_calls());
360   EXPECT_EQ(0, observer().detach_calls());
361
362   // Not a device
363   mount_info.mount_type = chromeos::MOUNT_TYPE_ARCHIVE;
364   MountDevice(chromeos::MOUNT_ERROR_NONE,
365               mount_info,
366               kUniqueId,
367               kDevice1Name,
368               kVendorName,
369               kProductName,
370               chromeos::DEVICE_TYPE_USB,
371               kDevice1SizeInBytes);
372   EXPECT_EQ(0, observer().attach_calls());
373   EXPECT_EQ(0, observer().detach_calls());
374
375   // Unsupported file system.
376   mount_info.mount_type = chromeos::MOUNT_TYPE_DEVICE;
377   mount_info.mount_condition =
378       chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
379   MountDevice(chromeos::MOUNT_ERROR_NONE,
380               mount_info,
381               kUniqueId,
382               kDevice1Name,
383               kVendorName,
384               kProductName,
385               chromeos::DEVICE_TYPE_USB,
386               kDevice1SizeInBytes);
387   EXPECT_EQ(0, observer().attach_calls());
388   EXPECT_EQ(0, observer().detach_calls());
389 }
390
391 TEST_F(StorageMonitorCrosTest, SDCardAttachDetach) {
392   base::FilePath mount_path1 = CreateMountPoint(kSDCardMountPoint1, true);
393   ASSERT_FALSE(mount_path1.empty());
394   DiskMountManager::MountPointInfo mount_info1(
395       kSDCardDeviceName1,
396       mount_path1.value(),
397       chromeos::MOUNT_TYPE_DEVICE,
398       chromeos::disks::MOUNT_CONDITION_NONE);
399   MountDevice(chromeos::MOUNT_ERROR_NONE,
400               mount_info1,
401               kUniqueId2,
402               kSDCardDeviceName1,
403               kVendorName,
404               kProductName,
405               chromeos::DEVICE_TYPE_SD,
406               kSDCardSizeInBytes);
407   EXPECT_EQ(1, observer().attach_calls());
408   EXPECT_EQ(0, observer().detach_calls());
409   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
410             observer().last_attached().device_id());
411   EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
412
413   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info1);
414   EXPECT_EQ(1, observer().attach_calls());
415   EXPECT_EQ(1, observer().detach_calls());
416   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
417             observer().last_detached().device_id());
418
419   base::FilePath mount_path2 = CreateMountPoint(kSDCardMountPoint2, true);
420   ASSERT_FALSE(mount_path2.empty());
421   DiskMountManager::MountPointInfo mount_info2(
422       kSDCardDeviceName2,
423       mount_path2.value(),
424       chromeos::MOUNT_TYPE_DEVICE,
425       chromeos::disks::MOUNT_CONDITION_NONE);
426   MountDevice(chromeos::MOUNT_ERROR_NONE,
427               mount_info2,
428               kUniqueId2,
429               kSDCardDeviceName2,
430               kVendorName,
431               kProductName,
432               chromeos::DEVICE_TYPE_SD,
433               kSDCardSizeInBytes);
434   EXPECT_EQ(2, observer().attach_calls());
435   EXPECT_EQ(1, observer().detach_calls());
436   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
437             observer().last_attached().device_id());
438   EXPECT_EQ(mount_path2.value(), observer().last_attached().location());
439
440   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info2);
441   EXPECT_EQ(2, observer().attach_calls());
442   EXPECT_EQ(2, observer().detach_calls());
443   EXPECT_EQ(GetDCIMDeviceId(kUniqueId2),
444             observer().last_detached().device_id());
445 }
446
447 TEST_F(StorageMonitorCrosTest, AttachDeviceWithEmptyLabel) {
448   base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
449   ASSERT_FALSE(mount_path1.empty());
450   DiskMountManager::MountPointInfo mount_info(
451       kEmptyDeviceLabel,
452       mount_path1.value(),
453       chromeos::MOUNT_TYPE_DEVICE,
454       chromeos::disks::MOUNT_CONDITION_NONE);
455   MountDevice(chromeos::MOUNT_ERROR_NONE,
456               mount_info,
457               kUniqueId1,
458               kEmptyDeviceLabel,
459               kVendorName,
460               kProductName,
461               chromeos::DEVICE_TYPE_USB,
462               kDevice1SizeInBytes);
463   EXPECT_EQ(1, observer().attach_calls());
464   EXPECT_EQ(0, observer().detach_calls());
465   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
466             observer().last_attached().device_id());
467   EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
468
469   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info);
470   EXPECT_EQ(1, observer().attach_calls());
471   EXPECT_EQ(1, observer().detach_calls());
472   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
473             observer().last_detached().device_id());
474 }
475
476 TEST_F(StorageMonitorCrosTest, GetStorageSize) {
477   base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
478   ASSERT_FALSE(mount_path1.empty());
479   DiskMountManager::MountPointInfo mount_info(
480       kEmptyDeviceLabel,
481       mount_path1.value(),
482       chromeos::MOUNT_TYPE_DEVICE,
483       chromeos::disks::MOUNT_CONDITION_NONE);
484   MountDevice(chromeos::MOUNT_ERROR_NONE,
485               mount_info,
486               kUniqueId1,
487               kEmptyDeviceLabel,
488               kVendorName,
489               kProductName,
490               chromeos::DEVICE_TYPE_USB,
491               kDevice1SizeInBytes);
492   EXPECT_EQ(1, observer().attach_calls());
493   EXPECT_EQ(0, observer().detach_calls());
494   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
495             observer().last_attached().device_id());
496   EXPECT_EQ(mount_path1.value(), observer().last_attached().location());
497
498   EXPECT_EQ(kDevice1SizeInBytes, GetDeviceStorageSize(mount_path1.value()));
499   UnmountDevice(chromeos::MOUNT_ERROR_NONE, mount_info);
500   EXPECT_EQ(1, observer().attach_calls());
501   EXPECT_EQ(1, observer().detach_calls());
502   EXPECT_EQ(GetDCIMDeviceId(kUniqueId1),
503             observer().last_detached().device_id());
504 }
505
506 void UnmountFake(const std::string& location,
507                  chromeos::UnmountOptions options,
508                  const DiskMountManager::UnmountPathCallback& cb) {
509   cb.Run(chromeos::MOUNT_ERROR_NONE);
510 }
511
512 TEST_F(StorageMonitorCrosTest, EjectTest) {
513   base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true);
514   ASSERT_FALSE(mount_path1.empty());
515   DiskMountManager::MountPointInfo mount_info(
516       kEmptyDeviceLabel,
517       mount_path1.value(),
518       chromeos::MOUNT_TYPE_DEVICE,
519       chromeos::disks::MOUNT_CONDITION_NONE);
520   MountDevice(chromeos::MOUNT_ERROR_NONE,
521               mount_info,
522               kUniqueId1,
523               kEmptyDeviceLabel,
524               kVendorName,
525               kProductName,
526               chromeos::DEVICE_TYPE_USB,
527               kDevice1SizeInBytes);
528   EXPECT_EQ(1, observer().attach_calls());
529   EXPECT_EQ(0, observer().detach_calls());
530
531   ON_CALL(*disk_mount_manager_mock_, UnmountPath(_, _, _))
532       .WillByDefault(testing::Invoke(&UnmountFake));
533   EXPECT_CALL(*disk_mount_manager_mock_,
534               UnmountPath(observer().last_attached().location(), _, _));
535   monitor_->EjectDevice(observer().last_attached().device_id(),
536                         base::Bind(&StorageMonitorCrosTest::EjectNotify,
537                                    base::Unretained(this)));
538   base::RunLoop().RunUntilIdle();
539
540   EXPECT_EQ(StorageMonitor::EJECT_OK, status_);
541 }
542
543 }  // namespace
544
545 }  // namespace storage_monitor