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 <string> 6 7 #include "base/file_util.h" 8 #include "base/files/scoped_temp_dir.h" 9 #include "base/run_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "base/synchronization/waitable_event.h" 12 #include "components/storage_monitor/media_storage_util.h" 13 #include "components/storage_monitor/removable_device_constants.h" 14 #include "components/storage_monitor/storage_monitor.h" 15 #include "components/storage_monitor/test_storage_monitor.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/test/test_browser_thread_bundle.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace { 21 22 const char kImageCaptureDeviceId[] = "ic:xyz"; 23 24 } // namespace 25 26 using content::BrowserThread; 27 28 namespace storage_monitor { 29 30 class MediaStorageUtilTest : public testing::Test { 31 public: 32 MediaStorageUtilTest() 33 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {} 34 virtual ~MediaStorageUtilTest() {} 35 36 // Verify mounted device type. 37 void CheckDCIMDeviceType(const base::FilePath& mount_point) { 38 EXPECT_TRUE(MediaStorageUtil::HasDcim(mount_point)); 39 } 40 41 void CheckNonDCIMDeviceType(const base::FilePath& mount_point) { 42 EXPECT_FALSE(MediaStorageUtil::HasDcim(mount_point)); 43 } 44 45 void ProcessAttach(const std::string& id, 46 const base::FilePath::StringType& location) { 47 StorageInfo info(id, location, base::string16(), base::string16(), 48 base::string16(), 0); 49 monitor_->receiver()->ProcessAttach(info); 50 } 51 52 protected: 53 // Create mount point for the test device. 54 base::FilePath CreateMountPoint(bool create_dcim_dir) { 55 base::FilePath path(scoped_temp_dir_.path()); 56 if (create_dcim_dir) 57 path = path.Append(kDCIMDirectoryName); 58 if (!base::CreateDirectory(path)) 59 return base::FilePath(); 60 return scoped_temp_dir_.path(); 61 } 62 63 virtual void SetUp() OVERRIDE { 64 monitor_ = TestStorageMonitor::CreateAndInstall(); 65 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); 66 } 67 68 virtual void TearDown() OVERRIDE { 69 WaitForFileThread(); 70 TestStorageMonitor::Destroy(); 71 } 72 73 static void PostQuitToUIThread() { 74 BrowserThread::PostTask(BrowserThread::UI, 75 FROM_HERE, 76 base::MessageLoop::QuitClosure()); 77 } 78 79 static void WaitForFileThread() { 80 BrowserThread::PostTask(BrowserThread::FILE, 81 FROM_HERE, 82 base::Bind(&PostQuitToUIThread)); 83 base::MessageLoop::current()->Run(); 84 } 85 86 private: 87 content::TestBrowserThreadBundle thread_bundle_; 88 TestStorageMonitor* monitor_; 89 base::ScopedTempDir scoped_temp_dir_; 90 }; 91 92 // Test to verify that HasDcim() function returns true for the given media 93 // device mount point. 94 TEST_F(MediaStorageUtilTest, MediaDeviceAttached) { 95 // Create a dummy mount point with DCIM Directory. 96 base::FilePath mount_point(CreateMountPoint(true)); 97 ASSERT_FALSE(mount_point.empty()); 98 BrowserThread::PostTask( 99 BrowserThread::FILE, FROM_HERE, 100 base::Bind(&MediaStorageUtilTest::CheckDCIMDeviceType, 101 base::Unretained(this), mount_point)); 102 base::RunLoop().RunUntilIdle(); 103 } 104 105 // Test to verify that HasDcim() function returns false for a given non-media 106 // device mount point. 107 TEST_F(MediaStorageUtilTest, NonMediaDeviceAttached) { 108 // Create a dummy mount point without DCIM Directory. 109 base::FilePath mount_point(CreateMountPoint(false)); 110 ASSERT_FALSE(mount_point.empty()); 111 BrowserThread::PostTask( 112 BrowserThread::FILE, FROM_HERE, 113 base::Bind(&MediaStorageUtilTest::CheckNonDCIMDeviceType, 114 base::Unretained(this), mount_point)); 115 base::RunLoop().RunUntilIdle(); 116 } 117 118 TEST_F(MediaStorageUtilTest, CanCreateFileSystemForImageCapture) { 119 EXPECT_TRUE(MediaStorageUtil::CanCreateFileSystem(kImageCaptureDeviceId, 120 base::FilePath())); 121 EXPECT_FALSE(MediaStorageUtil::CanCreateFileSystem( 122 "dcim:xyz", base::FilePath())); 123 EXPECT_FALSE(MediaStorageUtil::CanCreateFileSystem( 124 "dcim:xyz", base::FilePath(FILE_PATH_LITERAL("relative")))); 125 EXPECT_FALSE(MediaStorageUtil::CanCreateFileSystem( 126 "dcim:xyz", base::FilePath(FILE_PATH_LITERAL("../refparent")))); 127 } 128 129 TEST_F(MediaStorageUtilTest, DetectDeviceFiltered) { 130 MediaStorageUtil::DeviceIdSet devices; 131 devices.insert(kImageCaptureDeviceId); 132 133 base::WaitableEvent event(true, false); 134 base::Closure signal_event = 135 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)); 136 137 // We need signal_event to be executed on the FILE thread, as the test thread 138 // is blocked. Therefore, we invoke FilterAttachedDevices on the FILE thread. 139 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 140 base::Bind(&MediaStorageUtil::FilterAttachedDevices, 141 base::Unretained(&devices), signal_event)); 142 event.Wait(); 143 EXPECT_FALSE(devices.find(kImageCaptureDeviceId) != devices.end()); 144 145 ProcessAttach(kImageCaptureDeviceId, FILE_PATH_LITERAL("/location")); 146 devices.insert(kImageCaptureDeviceId); 147 event.Reset(); 148 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 149 base::Bind(&MediaStorageUtil::FilterAttachedDevices, 150 base::Unretained(&devices), signal_event)); 151 event.Wait(); 152 153 EXPECT_TRUE(devices.find(kImageCaptureDeviceId) != devices.end()); 154 } 155 156 } // namespace storage_monitor 157