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.
5 // StorageMonitorLinux unit tests.
7 #include "components/storage_monitor/storage_monitor_linux.h"
14 #include "base/file_util.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/run_loop.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "components/storage_monitor/mock_removable_storage_observer.h"
21 #include "components/storage_monitor/removable_device_constants.h"
22 #include "components/storage_monitor/storage_info.h"
23 #include "components/storage_monitor/storage_monitor.h"
24 #include "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
25 #include "components/storage_monitor/test_storage_monitor.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "testing/gtest/include/gtest/gtest.h"
31 const char kValidFS[] = "vfat";
32 const char kInvalidFS[] = "invalidfs";
34 const char kInvalidPath[] = "invalid path does not exist";
36 const char kDeviceDCIM1[] = "d1";
37 const char kDeviceDCIM2[] = "d2";
38 const char kDeviceDCIM3[] = "d3";
39 const char kDeviceNoDCIM[] = "d4";
40 const char kDeviceFixed[] = "d5";
42 const char kInvalidDevice[] = "invalid_device";
44 const char kMountPointA[] = "mnt_a";
45 const char kMountPointB[] = "mnt_b";
46 const char kMountPointC[] = "mnt_c";
48 struct TestDeviceData {
49 const char* device_path;
50 const char* unique_id;
51 StorageInfo::Type type;
52 uint64 partition_size_in_bytes;
55 const TestDeviceData kTestDeviceData[] = {
56 { kDeviceDCIM1, "UUID:FFF0-000F",
57 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, 88788 },
58 { kDeviceDCIM2, "VendorModelSerial:ComName:Model2010:8989",
59 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
61 { kDeviceDCIM3, "VendorModelSerial:::WEM319X792",
62 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, 22837 },
63 { kDeviceNoDCIM, "UUID:ABCD-1234",
64 StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM, 512 },
65 { kDeviceFixed, "UUID:743A-2349",
66 StorageInfo::FIXED_MASS_STORAGE, 17282 },
69 scoped_ptr<StorageInfo> GetDeviceInfo(const base::FilePath& device_path,
70 const base::FilePath& mount_point) {
71 bool device_found = false;
73 for (; i < arraysize(kTestDeviceData); i++) {
74 if (device_path.value() == kTestDeviceData[i].device_path) {
80 scoped_ptr<StorageInfo> storage_info;
83 return storage_info.Pass();
86 StorageInfo::Type type = kTestDeviceData[i].type;
87 storage_info.reset(new StorageInfo(
88 StorageInfo::MakeDeviceId(type, kTestDeviceData[i].unique_id),
91 base::ASCIIToUTF16("volume label"),
92 base::ASCIIToUTF16("vendor name"),
93 base::ASCIIToUTF16("model name"),
94 kTestDeviceData[i].partition_size_in_bytes));
95 return storage_info.Pass();
98 uint64 GetDevicePartitionSize(const std::string& device) {
99 for (size_t i = 0; i < arraysize(kTestDeviceData); ++i) {
100 if (device == kTestDeviceData[i].device_path)
101 return kTestDeviceData[i].partition_size_in_bytes;
106 std::string GetDeviceId(const std::string& device) {
107 for (size_t i = 0; i < arraysize(kTestDeviceData); ++i) {
108 if (device == kTestDeviceData[i].device_path) {
109 return StorageInfo::MakeDeviceId(kTestDeviceData[i].type,
110 kTestDeviceData[i].unique_id);
113 if (device == kInvalidDevice) {
114 return StorageInfo::MakeDeviceId(StorageInfo::FIXED_MASS_STORAGE,
117 return std::string();
120 class TestStorageMonitorLinux : public StorageMonitorLinux {
122 explicit TestStorageMonitorLinux(const base::FilePath& path)
123 : StorageMonitorLinux(path) {
124 SetMediaTransferProtocolManagerForTest(
125 new TestMediaTransferProtocolManagerLinux());
126 SetGetDeviceInfoCallbackForTest(base::Bind(&GetDeviceInfo));
128 virtual ~TestStorageMonitorLinux() {}
131 virtual void UpdateMtab(
132 const MtabWatcherLinux::MountPointDeviceMap& new_mtab) OVERRIDE {
133 StorageMonitorLinux::UpdateMtab(new_mtab);
134 base::MessageLoopProxy::current()->PostTask(
135 FROM_HERE, base::MessageLoop::QuitClosure());
138 DISALLOW_COPY_AND_ASSIGN(TestStorageMonitorLinux);
141 class StorageMonitorLinuxTest : public testing::Test {
143 struct MtabTestData {
144 MtabTestData(const std::string& mount_device,
145 const std::string& mount_point,
146 const std::string& mount_type)
147 : mount_device(mount_device),
148 mount_point(mount_point),
149 mount_type(mount_type) {
152 const std::string mount_device;
153 const std::string mount_point;
154 const std::string mount_type;
157 StorageMonitorLinuxTest()
158 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
159 virtual ~StorageMonitorLinuxTest() {}
162 virtual void SetUp() OVERRIDE {
163 // Create and set up a temp dir with files for the test.
164 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
165 base::FilePath test_dir = scoped_temp_dir_.path().AppendASCII("test_etc");
166 ASSERT_TRUE(base::CreateDirectory(test_dir));
167 mtab_file_ = test_dir.AppendASCII("test_mtab");
168 MtabTestData initial_test_data[] = {
169 MtabTestData("dummydevice", "dummydir", kInvalidFS),
171 WriteToMtab(initial_test_data,
172 arraysize(initial_test_data),
173 true /* overwrite */);
175 monitor_.reset(new TestStorageMonitorLinux(mtab_file_));
177 mock_storage_observer_.reset(new MockRemovableStorageObserver);
178 monitor_->AddObserver(mock_storage_observer_.get());
181 base::RunLoop().RunUntilIdle();
184 virtual void TearDown() OVERRIDE {
185 base::RunLoop().RunUntilIdle();
186 monitor_->RemoveObserver(mock_storage_observer_.get());
187 base::RunLoop().RunUntilIdle();
189 // Linux storage monitor must be destroyed on the UI thread, so do it here.
193 // Append mtab entries from the |data| array of size |data_size| to the mtab
194 // file, and run the message loop.
195 void AppendToMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
196 WriteToMtab(data, data_size, false /* do not overwrite */);
197 base::RunLoop().Run();
200 // Overwrite the mtab file with mtab entries from the |data| array of size
201 // |data_size|, and run the message loop.
202 void OverwriteMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
203 WriteToMtab(data, data_size, true /* overwrite */);
204 base::RunLoop().Run();
207 // Simplied version of OverwriteMtabAndRunLoop() that just deletes all the
208 // entries in the mtab file.
209 void WriteEmptyMtabAndRunLoop() {
210 OverwriteMtabAndRunLoop(NULL, // No data.
211 0); // No data length.
214 // Create a directory named |dir| relative to the test directory.
215 // It has a DCIM directory, so StorageMonitorLinux recognizes it as a media
217 base::FilePath CreateMountPointWithDCIMDir(const std::string& dir) {
218 return CreateMountPoint(dir, true /* create DCIM dir */);
221 // Create a directory named |dir| relative to the test directory.
222 // It does not have a DCIM directory, so StorageMonitorLinux does not
223 // recognize it as a media directory.
224 base::FilePath CreateMountPointWithoutDCIMDir(const std::string& dir) {
225 return CreateMountPoint(dir, false /* do not create DCIM dir */);
228 void RemoveDCIMDirFromMountPoint(const std::string& dir) {
229 base::FilePath dcim =
230 scoped_temp_dir_.path().AppendASCII(dir).Append(kDCIMDirectoryName);
231 base::DeleteFile(dcim, false);
234 MockRemovableStorageObserver& observer() {
235 return *mock_storage_observer_;
238 StorageMonitor* notifier() {
239 return monitor_.get();
242 uint64 GetStorageSize(const base::FilePath& path) {
244 if (!notifier()->GetStorageInfoForPath(path, &info))
247 return info.total_size_in_bytes();
251 // Create a directory named |dir| relative to the test directory.
252 // Set |with_dcim_dir| to true if the created directory will have a "DCIM"
254 // Returns the full path to the created directory on success, or an empty
256 base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir) {
257 base::FilePath return_path(scoped_temp_dir_.path());
258 return_path = return_path.AppendASCII(dir);
259 base::FilePath path(return_path);
261 path = path.Append(kDCIMDirectoryName);
262 if (!base::CreateDirectory(path))
263 return base::FilePath();
267 // Write the test mtab data to |mtab_file_|.
268 // |data| is an array of mtab entries.
269 // |data_size| is the array size of |data|.
270 // |overwrite| specifies whether to overwrite |mtab_file_|.
271 void WriteToMtab(const MtabTestData* data,
274 FILE* file = setmntent(mtab_file_.value().c_str(), overwrite ? "w" : "a");
277 // Due to the glibc *mntent() interface design, which is out of our
278 // control, the mtnent struct has several char* fields, even though
279 // addmntent() does not write to them in the calls below. To make the
280 // compiler happy while avoiding making additional copies of strings,
281 // we just const_cast() the strings' c_str()s.
282 // Assuming addmntent() does not write to the char* fields, this is safe.
283 // It is unlikely the platforms this test suite runs on will have an
284 // addmntent() implementation that does change the char* fields. If that
285 // was ever the case, the test suite will start crashing or failing.
287 static const char kMountOpts[] = "rw";
288 entry.mnt_opts = const_cast<char*>(kMountOpts);
290 entry.mnt_passno = 0;
291 for (size_t i = 0; i < data_size; ++i) {
292 entry.mnt_fsname = const_cast<char*>(data[i].mount_device.c_str());
293 entry.mnt_dir = const_cast<char*>(data[i].mount_point.c_str());
294 entry.mnt_type = const_cast<char*>(data[i].mount_type.c_str());
295 ASSERT_EQ(0, addmntent(file, &entry));
297 ASSERT_EQ(1, endmntent(file));
300 content::TestBrowserThreadBundle thread_bundle_;
302 scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
304 // Temporary directory for created test data.
305 base::ScopedTempDir scoped_temp_dir_;
306 // Path to the test mtab file.
307 base::FilePath mtab_file_;
309 scoped_ptr<TestStorageMonitorLinux> monitor_;
311 DISALLOW_COPY_AND_ASSIGN(StorageMonitorLinuxTest);
314 // Simple test case where we attach and detach a media device.
315 TEST_F(StorageMonitorLinuxTest, BasicAttachDetach) {
316 base::FilePath test_path = CreateMountPointWithDCIMDir(kMountPointA);
317 ASSERT_FALSE(test_path.empty());
318 MtabTestData test_data[] = {
319 MtabTestData(kDeviceDCIM2, test_path.value(), kValidFS),
320 MtabTestData(kDeviceFixed, kInvalidPath, kValidFS),
322 // Only |kDeviceDCIM2| should be attached, since |kDeviceFixed| has a bad
324 AppendToMtabAndRunLoop(test_data, arraysize(test_data));
326 EXPECT_EQ(1, observer().attach_calls());
327 EXPECT_EQ(0, observer().detach_calls());
328 EXPECT_EQ(GetDeviceId(kDeviceDCIM2), observer().last_attached().device_id());
329 EXPECT_EQ(base::string16(), observer().last_attached().name());
330 EXPECT_EQ(test_path.value(), observer().last_attached().location());
332 // |kDeviceDCIM2| should be detached here.
333 WriteEmptyMtabAndRunLoop();
334 EXPECT_EQ(1, observer().attach_calls());
335 EXPECT_EQ(1, observer().detach_calls());
336 EXPECT_EQ(GetDeviceId(kDeviceDCIM2), observer().last_detached().device_id());
339 // Only removable devices are recognized.
340 TEST_F(StorageMonitorLinuxTest, Removable) {
341 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
342 ASSERT_FALSE(test_path_a.empty());
343 MtabTestData test_data1[] = {
344 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
346 // |kDeviceDCIM1| should be attached as expected.
347 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
349 EXPECT_EQ(1, observer().attach_calls());
350 EXPECT_EQ(0, observer().detach_calls());
351 EXPECT_EQ(GetDeviceId(kDeviceDCIM1), observer().last_attached().device_id());
352 EXPECT_EQ(base::string16(), observer().last_attached().name());
353 EXPECT_EQ(test_path_a.value(), observer().last_attached().location());
355 // This should do nothing, since |kDeviceFixed| is not removable.
356 base::FilePath test_path_b = CreateMountPointWithoutDCIMDir(kMountPointB);
357 ASSERT_FALSE(test_path_b.empty());
358 MtabTestData test_data2[] = {
359 MtabTestData(kDeviceFixed, test_path_b.value(), kValidFS),
361 AppendToMtabAndRunLoop(test_data2, arraysize(test_data2));
362 EXPECT_EQ(1, observer().attach_calls());
363 EXPECT_EQ(0, observer().detach_calls());
365 // |kDeviceDCIM1| should be detached as expected.
366 WriteEmptyMtabAndRunLoop();
367 EXPECT_EQ(1, observer().attach_calls());
368 EXPECT_EQ(1, observer().detach_calls());
369 EXPECT_EQ(GetDeviceId(kDeviceDCIM1), observer().last_detached().device_id());
371 // |kDeviceNoDCIM| should be attached as expected.
372 MtabTestData test_data3[] = {
373 MtabTestData(kDeviceNoDCIM, test_path_b.value(), kValidFS),
375 AppendToMtabAndRunLoop(test_data3, arraysize(test_data3));
376 EXPECT_EQ(2, observer().attach_calls());
377 EXPECT_EQ(1, observer().detach_calls());
378 EXPECT_EQ(GetDeviceId(kDeviceNoDCIM), observer().last_attached().device_id());
379 EXPECT_EQ(base::string16(), observer().last_attached().name());
380 EXPECT_EQ(test_path_b.value(), observer().last_attached().location());
382 // |kDeviceNoDCIM| should be detached as expected.
383 WriteEmptyMtabAndRunLoop();
384 EXPECT_EQ(2, observer().attach_calls());
385 EXPECT_EQ(2, observer().detach_calls());
386 EXPECT_EQ(GetDeviceId(kDeviceNoDCIM), observer().last_detached().device_id());
389 // More complicated test case with multiple devices on multiple mount points.
390 TEST_F(StorageMonitorLinuxTest, SwapMountPoints) {
391 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
392 base::FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
393 ASSERT_FALSE(test_path_a.empty());
394 ASSERT_FALSE(test_path_b.empty());
396 // Attach two devices.
397 // (*'d mounts are those StorageMonitor knows about.)
398 // kDeviceDCIM1 -> kMountPointA *
399 // kDeviceDCIM2 -> kMountPointB *
400 MtabTestData test_data1[] = {
401 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
402 MtabTestData(kDeviceDCIM2, test_path_b.value(), kValidFS),
404 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
405 EXPECT_EQ(2, observer().attach_calls());
406 EXPECT_EQ(0, observer().detach_calls());
408 // Detach two devices from old mount points and attach the devices at new
410 // kDeviceDCIM1 -> kMountPointB *
411 // kDeviceDCIM2 -> kMountPointA *
412 MtabTestData test_data2[] = {
413 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
414 MtabTestData(kDeviceDCIM2, test_path_a.value(), kValidFS),
416 OverwriteMtabAndRunLoop(test_data2, arraysize(test_data2));
417 EXPECT_EQ(4, observer().attach_calls());
418 EXPECT_EQ(2, observer().detach_calls());
420 // Detach all devices.
421 WriteEmptyMtabAndRunLoop();
422 EXPECT_EQ(4, observer().attach_calls());
423 EXPECT_EQ(4, observer().detach_calls());
426 // More complicated test case with multiple devices on multiple mount points.
427 TEST_F(StorageMonitorLinuxTest, MultiDevicesMultiMountPoints) {
428 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
429 base::FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
430 ASSERT_FALSE(test_path_a.empty());
431 ASSERT_FALSE(test_path_b.empty());
433 // Attach two devices.
434 // (*'d mounts are those StorageMonitor knows about.)
435 // kDeviceDCIM1 -> kMountPointA *
436 // kDeviceDCIM2 -> kMountPointB *
437 MtabTestData test_data1[] = {
438 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
439 MtabTestData(kDeviceDCIM2, test_path_b.value(), kValidFS),
441 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
442 EXPECT_EQ(2, observer().attach_calls());
443 EXPECT_EQ(0, observer().detach_calls());
445 // Attach |kDeviceDCIM1| to |kMountPointB|.
446 // |kDeviceDCIM2| is inaccessible, so it is detached. |kDeviceDCIM1| has been
447 // attached at |kMountPointB|, but is still accessible from |kMountPointA|.
448 // kDeviceDCIM1 -> kMountPointA *
449 // kDeviceDCIM2 -> kMountPointB
450 // kDeviceDCIM1 -> kMountPointB
451 MtabTestData test_data2[] = {
452 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
454 AppendToMtabAndRunLoop(test_data2, arraysize(test_data2));
455 EXPECT_EQ(2, observer().attach_calls());
456 EXPECT_EQ(1, observer().detach_calls());
458 // Detach |kDeviceDCIM1| from |kMountPointA|, causing a detach and attach
460 // kDeviceDCIM2 -> kMountPointB
461 // kDeviceDCIM1 -> kMountPointB *
462 MtabTestData test_data3[] = {
463 MtabTestData(kDeviceDCIM2, test_path_b.value(), kValidFS),
464 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
466 OverwriteMtabAndRunLoop(test_data3, arraysize(test_data3));
467 EXPECT_EQ(3, observer().attach_calls());
468 EXPECT_EQ(2, observer().detach_calls());
470 // Attach |kDeviceDCIM1| to |kMountPointA|.
471 // kDeviceDCIM2 -> kMountPointB
472 // kDeviceDCIM1 -> kMountPointB *
473 // kDeviceDCIM1 -> kMountPointA
474 MtabTestData test_data4[] = {
475 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
477 AppendToMtabAndRunLoop(test_data4, arraysize(test_data4));
478 EXPECT_EQ(3, observer().attach_calls());
479 EXPECT_EQ(2, observer().detach_calls());
481 // Detach |kDeviceDCIM1| from |kMountPointB|.
482 // kDeviceDCIM1 -> kMountPointA *
483 // kDeviceDCIM2 -> kMountPointB *
484 OverwriteMtabAndRunLoop(test_data1, arraysize(test_data1));
485 EXPECT_EQ(5, observer().attach_calls());
486 EXPECT_EQ(3, observer().detach_calls());
488 // Detach all devices.
489 WriteEmptyMtabAndRunLoop();
490 EXPECT_EQ(5, observer().attach_calls());
491 EXPECT_EQ(5, observer().detach_calls());
494 TEST_F(StorageMonitorLinuxTest, MultipleMountPointsWithNonDCIMDevices) {
495 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
496 base::FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
497 ASSERT_FALSE(test_path_a.empty());
498 ASSERT_FALSE(test_path_b.empty());
500 // Attach to one first.
501 // (*'d mounts are those StorageMonitor knows about.)
502 // kDeviceDCIM1 -> kMountPointA *
503 MtabTestData test_data1[] = {
504 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
506 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
507 EXPECT_EQ(1, observer().attach_calls());
508 EXPECT_EQ(0, observer().detach_calls());
510 // Attach |kDeviceDCIM1| to |kMountPointB|.
511 // kDeviceDCIM1 -> kMountPointA *
512 // kDeviceDCIM1 -> kMountPointB
513 MtabTestData test_data2[] = {
514 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
516 AppendToMtabAndRunLoop(test_data2, arraysize(test_data2));
517 EXPECT_EQ(1, observer().attach_calls());
518 EXPECT_EQ(0, observer().detach_calls());
520 // Attach |kDeviceFixed| (a non-removable device) to |kMountPointA|.
521 // kDeviceDCIM1 -> kMountPointA
522 // kDeviceDCIM1 -> kMountPointB *
523 // kDeviceFixed -> kMountPointA
524 MtabTestData test_data3[] = {
525 MtabTestData(kDeviceFixed, test_path_a.value(), kValidFS),
527 RemoveDCIMDirFromMountPoint(kMountPointA);
528 AppendToMtabAndRunLoop(test_data3, arraysize(test_data3));
529 EXPECT_EQ(2, observer().attach_calls());
530 EXPECT_EQ(1, observer().detach_calls());
532 // Detach |kDeviceFixed|.
533 // kDeviceDCIM1 -> kMountPointA
534 // kDeviceDCIM1 -> kMountPointB *
535 MtabTestData test_data4[] = {
536 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
537 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
539 CreateMountPointWithDCIMDir(kMountPointA);
540 OverwriteMtabAndRunLoop(test_data4, arraysize(test_data4));
541 EXPECT_EQ(2, observer().attach_calls());
542 EXPECT_EQ(1, observer().detach_calls());
544 // Attach |kDeviceNoDCIM| (a non-DCIM device) to |kMountPointB|.
545 // kDeviceDCIM1 -> kMountPointA *
546 // kDeviceDCIM1 -> kMountPointB
547 // kDeviceNoDCIM -> kMountPointB *
548 MtabTestData test_data5[] = {
549 MtabTestData(kDeviceNoDCIM, test_path_b.value(), kValidFS),
551 base::DeleteFile(test_path_b.Append(kDCIMDirectoryName), false);
552 AppendToMtabAndRunLoop(test_data5, arraysize(test_data5));
553 EXPECT_EQ(4, observer().attach_calls());
554 EXPECT_EQ(2, observer().detach_calls());
556 // Detach |kDeviceNoDCIM|.
557 // kDeviceDCIM1 -> kMountPointA *
558 // kDeviceDCIM1 -> kMountPointB
559 MtabTestData test_data6[] = {
560 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
561 MtabTestData(kDeviceDCIM1, test_path_b.value(), kValidFS),
563 CreateMountPointWithDCIMDir(kMountPointB);
564 OverwriteMtabAndRunLoop(test_data6, arraysize(test_data6));
565 EXPECT_EQ(4, observer().attach_calls());
566 EXPECT_EQ(3, observer().detach_calls());
568 // Detach |kDeviceDCIM1| from |kMountPointB|.
569 // kDeviceDCIM1 -> kMountPointA *
570 OverwriteMtabAndRunLoop(test_data1, arraysize(test_data1));
571 EXPECT_EQ(4, observer().attach_calls());
572 EXPECT_EQ(3, observer().detach_calls());
574 // Detach all devices.
575 WriteEmptyMtabAndRunLoop();
576 EXPECT_EQ(4, observer().attach_calls());
577 EXPECT_EQ(4, observer().detach_calls());
580 TEST_F(StorageMonitorLinuxTest, DeviceLookUp) {
581 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
582 base::FilePath test_path_b = CreateMountPointWithoutDCIMDir(kMountPointB);
583 base::FilePath test_path_c = CreateMountPointWithoutDCIMDir(kMountPointC);
584 ASSERT_FALSE(test_path_a.empty());
585 ASSERT_FALSE(test_path_b.empty());
586 ASSERT_FALSE(test_path_c.empty());
588 // Attach to one first.
589 // (starred mounts are those StorageMonitor knows about.)
590 // kDeviceDCIM1 -> kMountPointA *
591 // kDeviceNoDCIM -> kMountPointB *
592 // kDeviceFixed -> kMountPointC
593 MtabTestData test_data1[] = {
594 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
595 MtabTestData(kDeviceNoDCIM, test_path_b.value(), kValidFS),
596 MtabTestData(kDeviceFixed, test_path_c.value(), kValidFS),
598 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
599 EXPECT_EQ(2, observer().attach_calls());
600 EXPECT_EQ(0, observer().detach_calls());
602 StorageInfo device_info;
603 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_a, &device_info));
604 EXPECT_EQ(GetDeviceId(kDeviceDCIM1), device_info.device_id());
605 EXPECT_EQ(test_path_a.value(), device_info.location());
606 EXPECT_EQ(base::string16(), device_info.name());
607 EXPECT_EQ(88788ULL, device_info.total_size_in_bytes());
608 EXPECT_EQ(base::ASCIIToUTF16("volume label"), device_info.storage_label());
609 EXPECT_EQ(base::ASCIIToUTF16("vendor name"), device_info.vendor_name());
610 EXPECT_EQ(base::ASCIIToUTF16("model name"), device_info.model_name());
612 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_b, &device_info));
613 EXPECT_EQ(GetDeviceId(kDeviceNoDCIM), device_info.device_id());
614 EXPECT_EQ(test_path_b.value(), device_info.location());
615 EXPECT_EQ(base::string16(), device_info.name());
617 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_c, &device_info));
618 EXPECT_EQ(GetDeviceId(kDeviceFixed), device_info.device_id());
619 EXPECT_EQ(test_path_c.value(), device_info.location());
620 EXPECT_EQ(base::string16(), device_info.name());
623 EXPECT_FALSE(notifier()->GetStorageInfoForPath(base::FilePath(kInvalidPath),
626 // Test filling in of the mount point.
628 notifier()->GetStorageInfoForPath(test_path_a.Append("some/other/path"),
630 EXPECT_EQ(GetDeviceId(kDeviceDCIM1), device_info.device_id());
631 EXPECT_EQ(test_path_a.value(), device_info.location());
632 EXPECT_EQ(base::string16(), device_info.name());
634 // One device attached at multiple points.
635 // kDeviceDCIM1 -> kMountPointA *
636 // kDeviceFixed -> kMountPointB
637 // kDeviceFixed -> kMountPointC
638 MtabTestData test_data2[] = {
639 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
640 MtabTestData(kDeviceFixed, test_path_b.value(), kValidFS),
641 MtabTestData(kDeviceFixed, test_path_c.value(), kValidFS),
643 AppendToMtabAndRunLoop(test_data2, arraysize(test_data2));
645 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_a, &device_info));
646 EXPECT_EQ(GetDeviceId(kDeviceDCIM1), device_info.device_id());
648 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_b, &device_info));
649 EXPECT_EQ(GetDeviceId(kDeviceFixed), device_info.device_id());
651 EXPECT_TRUE(notifier()->GetStorageInfoForPath(test_path_c, &device_info));
652 EXPECT_EQ(GetDeviceId(kDeviceFixed), device_info.device_id());
654 EXPECT_EQ(2, observer().attach_calls());
655 EXPECT_EQ(1, observer().detach_calls());
658 TEST_F(StorageMonitorLinuxTest, DevicePartitionSize) {
659 base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
660 base::FilePath test_path_b = CreateMountPointWithoutDCIMDir(kMountPointB);
661 ASSERT_FALSE(test_path_a.empty());
662 ASSERT_FALSE(test_path_b.empty());
664 MtabTestData test_data1[] = {
665 MtabTestData(kDeviceDCIM1, test_path_a.value(), kValidFS),
666 MtabTestData(kDeviceNoDCIM, test_path_b.value(), kValidFS),
667 MtabTestData(kDeviceFixed, kInvalidPath, kInvalidFS),
669 AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
670 EXPECT_EQ(2, observer().attach_calls());
671 EXPECT_EQ(0, observer().detach_calls());
673 EXPECT_EQ(GetDevicePartitionSize(kDeviceDCIM1),
674 GetStorageSize(test_path_a));
675 EXPECT_EQ(GetDevicePartitionSize(kDeviceNoDCIM),
676 GetStorageSize(test_path_b));
677 EXPECT_EQ(GetDevicePartitionSize(kInvalidPath),
678 GetStorageSize(base::FilePath(kInvalidPath)));