OLD | NEW |
| (Empty) |
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 // chromeos::RemovableDeviceNotificationsCros unit tests. | |
6 | |
7 #include "chrome/browser/storage_monitor/removable_device_notifications_chromeos
.h" | |
8 | |
9 #include "base/file_util.h" | |
10 #include "base/files/scoped_temp_dir.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "base/utf_string_conversions.h" | |
15 #include "chrome/browser/storage_monitor/media_storage_util.h" | |
16 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.h" | |
17 #include "chrome/browser/storage_monitor/removable_device_constants.h" | |
18 #include "chromeos/disks/mock_disk_mount_manager.h" | |
19 #include "content/public/test/test_browser_thread.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 namespace chromeos { | |
23 | |
24 namespace { | |
25 | |
26 using content::BrowserThread; | |
27 using disks::DiskMountManager; | |
28 using testing::_; | |
29 | |
30 const char kDeviceNameWithManufacturerDetails[] = "110 KB (CompanyA, Z101)"; | |
31 const char kDevice1[] = "/dev/d1"; | |
32 const char kDevice1Name[] = "d1"; | |
33 const char kDevice1NameWithSizeInfo[] = "110 KB d1"; | |
34 const char kDevice2[] = "/dev/disk/d2"; | |
35 const char kDevice2Name[] = "d2"; | |
36 const char kDevice2NameWithSizeInfo[] = "207 KB d2"; | |
37 const char kEmptyDeviceLabel[] = ""; | |
38 const char kMountPointA[] = "mnt_a"; | |
39 const char kMountPointB[] = "mnt_b"; | |
40 const char kSDCardDeviceName1[] = "8.6 MB Amy_SD"; | |
41 const char kSDCardDeviceName2[] = "8.6 MB SD Card"; | |
42 const char kSDCardMountPoint1[] = "media/removable/Amy_SD"; | |
43 const char kSDCardMountPoint2[] = "media/removable/SD Card"; | |
44 const char kProductName[] = "Z101"; | |
45 const char kUniqueId1[] = "FFFF-FFFF"; | |
46 const char kUniqueId2[] = "FFFF-FF0F"; | |
47 const char kVendorName[] = "CompanyA"; | |
48 | |
49 uint64 kDevice1SizeInBytes = 113048; | |
50 uint64 kDevice2SizeInBytes = 212312; | |
51 uint64 kSDCardSizeInBytes = 9000000; | |
52 | |
53 std::string GetDCIMDeviceId(const std::string& unique_id) { | |
54 return chrome::MediaStorageUtil::MakeDeviceId( | |
55 chrome::MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM, | |
56 chrome::kFSUniqueIdPrefix + unique_id); | |
57 } | |
58 | |
59 // Wrapper class to test RemovableDeviceNotificationsCros. | |
60 class RemovableDeviceNotificationsCrosTest : public testing::Test { | |
61 public: | |
62 RemovableDeviceNotificationsCrosTest(); | |
63 virtual ~RemovableDeviceNotificationsCrosTest(); | |
64 | |
65 protected: | |
66 // testing::Test: | |
67 virtual void SetUp() OVERRIDE; | |
68 virtual void TearDown() OVERRIDE; | |
69 | |
70 void MountDevice(MountError error_code, | |
71 const DiskMountManager::MountPointInfo& mount_info, | |
72 const std::string& unique_id, | |
73 const std::string& device_label, | |
74 const std::string& vendor_name, | |
75 const std::string& product_name, | |
76 DeviceType device_type, | |
77 uint64 device_size_in_bytes); | |
78 | |
79 void UnmountDevice(MountError error_code, | |
80 const DiskMountManager::MountPointInfo& mount_info); | |
81 | |
82 uint64 GetDeviceStorageSize(const std::string& device_location); | |
83 | |
84 // Create a directory named |dir| relative to the test directory. | |
85 // Set |with_dcim_dir| to true if the created directory will have a "DCIM" | |
86 // subdirectory. | |
87 // Returns the full path to the created directory on success, or an empty | |
88 // path on failure. | |
89 base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir); | |
90 | |
91 static void PostQuitToUIThread(); | |
92 static void WaitForFileThread(); | |
93 | |
94 chrome::MockRemovableStorageObserver& observer() { | |
95 return *mock_storage_observer_; | |
96 } | |
97 | |
98 private: | |
99 // The message loops and threads to run tests on. | |
100 MessageLoop ui_loop_; | |
101 content::TestBrowserThread ui_thread_; | |
102 content::TestBrowserThread file_thread_; | |
103 | |
104 // Temporary directory for created test data. | |
105 base::ScopedTempDir scoped_temp_dir_; | |
106 | |
107 // Objects that talks with RemovableDeviceNotificationsCros. | |
108 scoped_ptr<chrome::MockRemovableStorageObserver> mock_storage_observer_; | |
109 // Owned by DiskMountManager. | |
110 disks::MockDiskMountManager* disk_mount_manager_mock_; | |
111 | |
112 scoped_refptr<RemovableDeviceNotificationsCros> notifications_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(RemovableDeviceNotificationsCrosTest); | |
115 }; | |
116 | |
117 RemovableDeviceNotificationsCrosTest::RemovableDeviceNotificationsCrosTest() | |
118 : ui_thread_(BrowserThread::UI, &ui_loop_), | |
119 file_thread_(BrowserThread::FILE) { | |
120 } | |
121 | |
122 RemovableDeviceNotificationsCrosTest::~RemovableDeviceNotificationsCrosTest() { | |
123 } | |
124 | |
125 void RemovableDeviceNotificationsCrosTest::SetUp() { | |
126 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
127 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); | |
128 file_thread_.Start(); | |
129 disk_mount_manager_mock_ = new disks::MockDiskMountManager(); | |
130 DiskMountManager::InitializeForTesting(disk_mount_manager_mock_); | |
131 disk_mount_manager_mock_->SetupDefaultReplies(); | |
132 | |
133 mock_storage_observer_.reset(new chrome::MockRemovableStorageObserver); | |
134 | |
135 // Initialize the test subject. | |
136 notifications_ = new RemovableDeviceNotificationsCros(); | |
137 notifications_->AddObserver(mock_storage_observer_.get()); | |
138 } | |
139 | |
140 void RemovableDeviceNotificationsCrosTest::TearDown() { | |
141 notifications_->RemoveObserver(mock_storage_observer_.get()); | |
142 notifications_ = NULL; | |
143 | |
144 disk_mount_manager_mock_ = NULL; | |
145 DiskMountManager::Shutdown(); | |
146 WaitForFileThread(); | |
147 } | |
148 | |
149 void RemovableDeviceNotificationsCrosTest::MountDevice( | |
150 MountError error_code, | |
151 const DiskMountManager::MountPointInfo& mount_info, | |
152 const std::string& unique_id, | |
153 const std::string& device_label, | |
154 const std::string& vendor_name, | |
155 const std::string& product_name, | |
156 DeviceType device_type, | |
157 uint64 device_size_in_bytes) { | |
158 if (error_code == MOUNT_ERROR_NONE) { | |
159 disk_mount_manager_mock_->CreateDiskEntryForMountDevice( | |
160 mount_info, unique_id, device_label, vendor_name, product_name, | |
161 device_type, device_size_in_bytes); | |
162 } | |
163 notifications_->OnMountEvent(disks::DiskMountManager::MOUNTING, | |
164 error_code, | |
165 mount_info); | |
166 WaitForFileThread(); | |
167 } | |
168 | |
169 void RemovableDeviceNotificationsCrosTest::UnmountDevice( | |
170 MountError error_code, | |
171 const DiskMountManager::MountPointInfo& mount_info) { | |
172 notifications_->OnMountEvent(disks::DiskMountManager::UNMOUNTING, | |
173 error_code, | |
174 mount_info); | |
175 if (error_code == MOUNT_ERROR_NONE) | |
176 disk_mount_manager_mock_->RemoveDiskEntryForMountDevice(mount_info); | |
177 WaitForFileThread(); | |
178 } | |
179 | |
180 uint64 RemovableDeviceNotificationsCrosTest::GetDeviceStorageSize( | |
181 const std::string& device_location) { | |
182 return notifications_->GetStorageSize(device_location); | |
183 } | |
184 | |
185 base::FilePath RemovableDeviceNotificationsCrosTest::CreateMountPoint( | |
186 const std::string& dir, bool with_dcim_dir) { | |
187 base::FilePath return_path(scoped_temp_dir_.path()); | |
188 return_path = return_path.AppendASCII(dir); | |
189 base::FilePath path(return_path); | |
190 if (with_dcim_dir) | |
191 path = path.Append(chrome::kDCIMDirectoryName); | |
192 if (!file_util::CreateDirectory(path)) | |
193 return base::FilePath(); | |
194 return return_path; | |
195 } | |
196 | |
197 // static | |
198 void RemovableDeviceNotificationsCrosTest::PostQuitToUIThread() { | |
199 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
200 MessageLoop::QuitClosure()); | |
201 } | |
202 | |
203 // static | |
204 void RemovableDeviceNotificationsCrosTest::WaitForFileThread() { | |
205 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
206 base::Bind(&PostQuitToUIThread)); | |
207 MessageLoop::current()->Run(); | |
208 } | |
209 | |
210 // Simple test case where we attach and detach a media device. | |
211 TEST_F(RemovableDeviceNotificationsCrosTest, BasicAttachDetach) { | |
212 base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true); | |
213 ASSERT_FALSE(mount_path1.empty()); | |
214 DiskMountManager::MountPointInfo mount_info(kDevice1, | |
215 mount_path1.value(), | |
216 MOUNT_TYPE_DEVICE, | |
217 disks::MOUNT_CONDITION_NONE); | |
218 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId1, kDevice1Name, | |
219 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
220 EXPECT_EQ(1, observer().attach_calls()); | |
221 EXPECT_EQ(0, observer().detach_calls()); | |
222 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_attached().device_id); | |
223 EXPECT_EQ(ASCIIToUTF16(kDevice1NameWithSizeInfo), | |
224 observer().last_attached().name); | |
225 EXPECT_EQ(mount_path1.value(), observer().last_attached().location); | |
226 | |
227 UnmountDevice(MOUNT_ERROR_NONE, mount_info); | |
228 EXPECT_EQ(1, observer().attach_calls()); | |
229 EXPECT_EQ(1, observer().detach_calls()); | |
230 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_detached().device_id); | |
231 | |
232 base::FilePath mount_path2 = CreateMountPoint(kMountPointB, true); | |
233 ASSERT_FALSE(mount_path2.empty()); | |
234 DiskMountManager::MountPointInfo mount_info2(kDevice2, | |
235 mount_path2.value(), | |
236 MOUNT_TYPE_DEVICE, | |
237 disks::MOUNT_CONDITION_NONE); | |
238 MountDevice(MOUNT_ERROR_NONE, mount_info2, kUniqueId2, kDevice2Name, | |
239 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice2SizeInBytes); | |
240 EXPECT_EQ(2, observer().attach_calls()); | |
241 EXPECT_EQ(1, observer().detach_calls()); | |
242 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_attached().device_id); | |
243 EXPECT_EQ(ASCIIToUTF16(kDevice2NameWithSizeInfo), | |
244 observer().last_attached().name); | |
245 EXPECT_EQ(mount_path2.value(), observer().last_attached().location); | |
246 | |
247 UnmountDevice(MOUNT_ERROR_NONE, mount_info2); | |
248 EXPECT_EQ(2, observer().attach_calls()); | |
249 EXPECT_EQ(2, observer().detach_calls()); | |
250 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_detached().device_id); | |
251 } | |
252 | |
253 // Removable mass storage devices with no dcim folder are also recognized. | |
254 TEST_F(RemovableDeviceNotificationsCrosTest, NoDCIM) { | |
255 testing::Sequence mock_sequence; | |
256 base::FilePath mount_path = CreateMountPoint(kMountPointA, false); | |
257 const std::string kUniqueId = "FFFF-FFFF"; | |
258 ASSERT_FALSE(mount_path.empty()); | |
259 DiskMountManager::MountPointInfo mount_info(kDevice1, | |
260 mount_path.value(), | |
261 MOUNT_TYPE_DEVICE, | |
262 disks::MOUNT_CONDITION_NONE); | |
263 const std::string device_id = chrome::MediaStorageUtil::MakeDeviceId( | |
264 chrome::MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM, | |
265 chrome::kFSUniqueIdPrefix + kUniqueId); | |
266 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId, kDevice1Name, | |
267 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
268 EXPECT_EQ(1, observer().attach_calls()); | |
269 EXPECT_EQ(0, observer().detach_calls()); | |
270 EXPECT_EQ(device_id, observer().last_attached().device_id); | |
271 EXPECT_EQ(ASCIIToUTF16(kDevice1NameWithSizeInfo), | |
272 observer().last_attached().name); | |
273 EXPECT_EQ(mount_path.value(), observer().last_attached().location); | |
274 } | |
275 | |
276 // Non device mounts and mount errors are ignored. | |
277 TEST_F(RemovableDeviceNotificationsCrosTest, Ignore) { | |
278 testing::Sequence mock_sequence; | |
279 base::FilePath mount_path = CreateMountPoint(kMountPointA, true); | |
280 const std::string kUniqueId = "FFFF-FFFF"; | |
281 ASSERT_FALSE(mount_path.empty()); | |
282 | |
283 // Mount error. | |
284 DiskMountManager::MountPointInfo mount_info(kDevice1, | |
285 mount_path.value(), | |
286 MOUNT_TYPE_DEVICE, | |
287 disks::MOUNT_CONDITION_NONE); | |
288 MountDevice(MOUNT_ERROR_UNKNOWN, mount_info, kUniqueId, kDevice1Name, | |
289 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
290 EXPECT_EQ(0, observer().attach_calls()); | |
291 EXPECT_EQ(0, observer().detach_calls()); | |
292 | |
293 // Not a device | |
294 mount_info.mount_type = MOUNT_TYPE_ARCHIVE; | |
295 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId, kDevice1Name, | |
296 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
297 EXPECT_EQ(0, observer().attach_calls()); | |
298 EXPECT_EQ(0, observer().detach_calls()); | |
299 | |
300 // Unsupported file system. | |
301 mount_info.mount_type = MOUNT_TYPE_DEVICE; | |
302 mount_info.mount_condition = disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM; | |
303 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId, kDevice1Name, | |
304 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
305 EXPECT_EQ(0, observer().attach_calls()); | |
306 EXPECT_EQ(0, observer().detach_calls()); | |
307 } | |
308 | |
309 TEST_F(RemovableDeviceNotificationsCrosTest, SDCardAttachDetach) { | |
310 base::FilePath mount_path1 = CreateMountPoint(kSDCardMountPoint1, true); | |
311 ASSERT_FALSE(mount_path1.empty()); | |
312 DiskMountManager::MountPointInfo mount_info1(kSDCardDeviceName1, | |
313 mount_path1.value(), | |
314 MOUNT_TYPE_DEVICE, | |
315 disks::MOUNT_CONDITION_NONE); | |
316 MountDevice(MOUNT_ERROR_NONE, mount_info1, kUniqueId2, kSDCardDeviceName1, | |
317 kVendorName, kProductName, DEVICE_TYPE_SD, kSDCardSizeInBytes); | |
318 EXPECT_EQ(1, observer().attach_calls()); | |
319 EXPECT_EQ(0, observer().detach_calls()); | |
320 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_attached().device_id); | |
321 EXPECT_EQ(ASCIIToUTF16(kSDCardDeviceName1), | |
322 observer().last_attached().name); | |
323 EXPECT_EQ(mount_path1.value(), observer().last_attached().location); | |
324 | |
325 UnmountDevice(MOUNT_ERROR_NONE, mount_info1); | |
326 EXPECT_EQ(1, observer().attach_calls()); | |
327 EXPECT_EQ(1, observer().detach_calls()); | |
328 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_detached().device_id); | |
329 | |
330 base::FilePath mount_path2 = CreateMountPoint(kSDCardMountPoint2, true); | |
331 ASSERT_FALSE(mount_path2.empty()); | |
332 DiskMountManager::MountPointInfo mount_info2(kSDCardDeviceName2, | |
333 mount_path2.value(), | |
334 MOUNT_TYPE_DEVICE, | |
335 disks::MOUNT_CONDITION_NONE); | |
336 MountDevice(MOUNT_ERROR_NONE, mount_info2, kUniqueId2, kSDCardDeviceName2, | |
337 kVendorName, kProductName, DEVICE_TYPE_SD, kSDCardSizeInBytes); | |
338 EXPECT_EQ(2, observer().attach_calls()); | |
339 EXPECT_EQ(1, observer().detach_calls()); | |
340 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_attached().device_id); | |
341 EXPECT_EQ(ASCIIToUTF16(kSDCardDeviceName2), | |
342 observer().last_attached().name); | |
343 EXPECT_EQ(mount_path2.value(), observer().last_attached().location); | |
344 | |
345 UnmountDevice(MOUNT_ERROR_NONE, mount_info2); | |
346 EXPECT_EQ(2, observer().attach_calls()); | |
347 EXPECT_EQ(2, observer().detach_calls()); | |
348 EXPECT_EQ(GetDCIMDeviceId(kUniqueId2), observer().last_detached().device_id); | |
349 } | |
350 | |
351 TEST_F(RemovableDeviceNotificationsCrosTest, AttachDeviceWithEmptyLabel) { | |
352 base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true); | |
353 ASSERT_FALSE(mount_path1.empty()); | |
354 DiskMountManager::MountPointInfo mount_info(kEmptyDeviceLabel, | |
355 mount_path1.value(), | |
356 MOUNT_TYPE_DEVICE, | |
357 disks::MOUNT_CONDITION_NONE); | |
358 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId1, kEmptyDeviceLabel, | |
359 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
360 EXPECT_EQ(1, observer().attach_calls()); | |
361 EXPECT_EQ(0, observer().detach_calls()); | |
362 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_attached().device_id); | |
363 EXPECT_EQ(ASCIIToUTF16(kDeviceNameWithManufacturerDetails), | |
364 observer().last_attached().name); | |
365 EXPECT_EQ(mount_path1.value(), observer().last_attached().location); | |
366 | |
367 UnmountDevice(MOUNT_ERROR_NONE, mount_info); | |
368 EXPECT_EQ(1, observer().attach_calls()); | |
369 EXPECT_EQ(1, observer().detach_calls()); | |
370 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_detached().device_id); | |
371 } | |
372 | |
373 TEST_F(RemovableDeviceNotificationsCrosTest, GetStorageSize) { | |
374 base::FilePath mount_path1 = CreateMountPoint(kMountPointA, true); | |
375 ASSERT_FALSE(mount_path1.empty()); | |
376 DiskMountManager::MountPointInfo mount_info(kEmptyDeviceLabel, | |
377 mount_path1.value(), | |
378 MOUNT_TYPE_DEVICE, | |
379 disks::MOUNT_CONDITION_NONE); | |
380 MountDevice(MOUNT_ERROR_NONE, mount_info, kUniqueId1, kEmptyDeviceLabel, | |
381 kVendorName, kProductName, DEVICE_TYPE_USB, kDevice1SizeInBytes); | |
382 EXPECT_EQ(1, observer().attach_calls()); | |
383 EXPECT_EQ(0, observer().detach_calls()); | |
384 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_attached().device_id); | |
385 EXPECT_EQ(ASCIIToUTF16(kDeviceNameWithManufacturerDetails), | |
386 observer().last_attached().name); | |
387 EXPECT_EQ(mount_path1.value(), observer().last_attached().location); | |
388 | |
389 EXPECT_EQ(kDevice1SizeInBytes, GetDeviceStorageSize(mount_path1.value())); | |
390 UnmountDevice(MOUNT_ERROR_NONE, mount_info); | |
391 EXPECT_EQ(1, observer().attach_calls()); | |
392 EXPECT_EQ(1, observer().detach_calls()); | |
393 EXPECT_EQ(GetDCIMDeviceId(kUniqueId1), observer().last_detached().device_id); | |
394 } | |
395 | |
396 } // namespace | |
397 | |
398 } // namespace chromeos | |
OLD | NEW |