1 // Copyright 2013 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 <set> 6 #include <string> 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/file_util.h" 12 #include "base/files/scoped_temp_dir.h" 13 #include "base/run_loop.h" 14 #include "base/synchronization/waitable_event.h" 15 #include "base/time/time.h" 16 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h" 17 #include "chrome/browser/media_galleries/fileapi/itunes_file_util.h" 18 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" 19 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h" 20 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "content/public/test/mock_special_storage_policy.h" 23 #include "content/public/test/test_browser_thread.h" 24 #include "content/public/test/test_file_system_options.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 #include "webkit/browser/fileapi/async_file_util.h" 27 #include "webkit/browser/fileapi/external_mount_points.h" 28 #include "webkit/browser/fileapi/file_system_context.h" 29 #include "webkit/browser/fileapi/file_system_operation_context.h" 30 #include "webkit/browser/fileapi/file_system_operation_runner.h" 31 32 using fileapi::FileSystemOperationContext; 33 using fileapi::FileSystemOperation; 34 using fileapi::FileSystemURL; 35 36 namespace itunes { 37 38 namespace { 39 40 void ReadDirectoryTestHelperCallback( 41 base::RunLoop* run_loop, 42 FileSystemOperation::FileEntryList* contents, 43 bool* completed, base::File::Error error, 44 const FileSystemOperation::FileEntryList& file_list, 45 bool has_more) { 46 DCHECK(!*completed); 47 *completed = (!has_more && error == base::File::FILE_OK); 48 *contents = file_list; 49 run_loop->Quit(); 50 } 51 52 void ReadDirectoryTestHelper(fileapi::FileSystemOperationRunner* runner, 53 const FileSystemURL& url, 54 FileSystemOperation::FileEntryList* contents, 55 bool* completed) { 56 DCHECK(contents); 57 DCHECK(completed); 58 base::RunLoop run_loop; 59 runner->ReadDirectory( 60 url, base::Bind(&ReadDirectoryTestHelperCallback, &run_loop, contents, 61 completed)); 62 run_loop.Run(); 63 } 64 65 } // namespace 66 67 class TestITunesDataProvider : public ITunesDataProvider { 68 public: 69 explicit TestITunesDataProvider(const base::FilePath& fake_library_path) 70 : ITunesDataProvider(fake_library_path) { 71 EXPECT_TRUE(fake_auto_add_dir_.CreateUniqueTempDir()); 72 } 73 74 virtual ~TestITunesDataProvider() {} 75 76 virtual void RefreshData(const ReadyCallback& ready_callback) OVERRIDE { 77 ready_callback.Run(true /* success */); 78 } 79 80 virtual const base::FilePath& auto_add_path() const OVERRIDE { 81 return fake_auto_add_dir_.path(); 82 } 83 84 void SetProvideAutoAddDir(bool provide_auto_add_dir) { 85 if (provide_auto_add_dir) { 86 if (!fake_auto_add_dir_.IsValid()) 87 ASSERT_TRUE(fake_auto_add_dir_.CreateUniqueTempDir()); 88 } else { 89 ASSERT_TRUE(fake_auto_add_dir_.Delete()); 90 } 91 } 92 93 private: 94 base::ScopedTempDir fake_auto_add_dir_; 95 }; 96 97 class TestITunesFileUtil : public ITunesFileUtil { 98 public: 99 explicit TestITunesFileUtil(MediaPathFilter* media_path_filter, 100 ITunesDataProvider* data_provider) 101 : ITunesFileUtil(media_path_filter), 102 data_provider_(data_provider) { 103 } 104 virtual ~TestITunesFileUtil() {} 105 106 private: 107 virtual ITunesDataProvider* GetDataProvider() OVERRIDE { 108 return data_provider_; 109 } 110 111 ITunesDataProvider* data_provider_; 112 }; 113 114 class TestMediaFileSystemBackend : public MediaFileSystemBackend { 115 public: 116 TestMediaFileSystemBackend(const base::FilePath& profile_path, 117 ITunesFileUtil* itunes_file_util) 118 : MediaFileSystemBackend( 119 profile_path, 120 MediaFileSystemBackend::MediaTaskRunner().get()), 121 test_file_util_(itunes_file_util) {} 122 123 virtual fileapi::AsyncFileUtil* 124 GetAsyncFileUtil(fileapi::FileSystemType type) OVERRIDE { 125 if (type != fileapi::kFileSystemTypeItunes) 126 return NULL; 127 128 return test_file_util_.get(); 129 } 130 131 private: 132 scoped_ptr<fileapi::AsyncFileUtil> test_file_util_; 133 }; 134 135 class ItunesFileUtilTest : public testing::Test { 136 public: 137 ItunesFileUtilTest() 138 : io_thread_(content::BrowserThread::IO, &message_loop_) { 139 } 140 virtual ~ItunesFileUtilTest() {} 141 142 void SetUpDataProvider() { 143 ASSERT_TRUE(fake_library_dir_.CreateUniqueTempDir()); 144 ASSERT_EQ( 145 0, 146 base::WriteFile( 147 fake_library_dir_.path().AppendASCII(kITunesLibraryXML), 148 NULL, 149 0)); 150 151 itunes_data_provider_.reset( 152 new TestITunesDataProvider(fake_library_dir_.path())); 153 } 154 155 virtual void SetUp() OVERRIDE { 156 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); 157 ImportedMediaGalleryRegistry::GetInstance()->Initialize(); 158 159 scoped_refptr<quota::SpecialStoragePolicy> storage_policy = 160 new content::MockSpecialStoragePolicy(); 161 162 // Initialize fake ItunesDataProvider on media task runner thread. 163 MediaFileSystemBackend::MediaTaskRunner()->PostTask( 164 FROM_HERE, 165 base::Bind(&ItunesFileUtilTest::SetUpDataProvider, 166 base::Unretained(this))); 167 base::WaitableEvent event(true, false /* initially_signalled */); 168 MediaFileSystemBackend::MediaTaskRunner()->PostTask( 169 FROM_HERE, 170 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); 171 event.Wait(); 172 173 media_path_filter_.reset(new MediaPathFilter()); 174 ScopedVector<fileapi::FileSystemBackend> additional_providers; 175 additional_providers.push_back(new TestMediaFileSystemBackend( 176 profile_dir_.path(), 177 new TestITunesFileUtil(media_path_filter_.get(), 178 itunes_data_provider_.get()))); 179 180 file_system_context_ = new fileapi::FileSystemContext( 181 base::MessageLoopProxy::current().get(), 182 base::MessageLoopProxy::current().get(), 183 fileapi::ExternalMountPoints::CreateRefCounted().get(), 184 storage_policy.get(), 185 NULL, 186 additional_providers.Pass(), 187 std::vector<fileapi::URLRequestAutoMountHandler>(), 188 profile_dir_.path(), 189 content::CreateAllowFileAccessOptions()); 190 } 191 192 protected: 193 void TestNonexistentFolder(const std::string& path_append) { 194 FileSystemOperation::FileEntryList contents; 195 FileSystemURL url = CreateURL(path_append); 196 bool completed = false; 197 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 198 199 ASSERT_FALSE(completed); 200 } 201 202 FileSystemURL CreateURL(const std::string& path) const { 203 base::FilePath virtual_path = 204 ImportedMediaGalleryRegistry::GetInstance()->ImportedRoot(); 205 virtual_path = virtual_path.AppendASCII("itunes"); 206 virtual_path = virtual_path.AppendASCII(path); 207 return file_system_context_->CreateCrackedFileSystemURL( 208 GURL("http://www.example.com"), fileapi::kFileSystemTypeItunes, 209 virtual_path); 210 } 211 212 fileapi::FileSystemOperationRunner* operation_runner() const { 213 return file_system_context_->operation_runner(); 214 } 215 216 scoped_refptr<fileapi::FileSystemContext> file_system_context() const { 217 return file_system_context_; 218 } 219 220 TestITunesDataProvider* data_provider() const { 221 return itunes_data_provider_.get(); 222 } 223 224 private: 225 base::MessageLoop message_loop_; 226 content::TestBrowserThread io_thread_; 227 228 base::ScopedTempDir profile_dir_; 229 base::ScopedTempDir fake_library_dir_; 230 231 scoped_refptr<fileapi::FileSystemContext> file_system_context_; 232 scoped_ptr<MediaPathFilter> media_path_filter_; 233 scoped_ptr<TestITunesDataProvider> itunes_data_provider_; 234 235 DISALLOW_COPY_AND_ASSIGN(ItunesFileUtilTest); 236 }; 237 238 TEST_F(ItunesFileUtilTest, RootContents) { 239 FileSystemOperation::FileEntryList contents; 240 FileSystemURL url = CreateURL(""); 241 bool completed = false; 242 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 243 244 ASSERT_TRUE(completed); 245 ASSERT_EQ(2u, contents.size()); 246 247 EXPECT_FALSE(contents.front().is_directory); 248 EXPECT_TRUE(contents.back().is_directory); 249 250 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesLibraryXML).value(), 251 contents.front().name); 252 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMediaDir).value(), 253 contents.back().name); 254 } 255 256 TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsNoAutoAdd) { 257 data_provider()->SetProvideAutoAddDir(false); 258 259 FileSystemOperation::FileEntryList contents; 260 FileSystemURL url = CreateURL(kITunesMediaDir); 261 bool completed = false; 262 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 263 264 ASSERT_TRUE(completed); 265 ASSERT_EQ(1u, contents.size()); 266 267 EXPECT_TRUE(contents.front().is_directory); 268 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 269 contents.back().name); 270 } 271 272 TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsAutoAdd) { 273 data_provider()->SetProvideAutoAddDir(true); 274 275 FileSystemOperation::FileEntryList contents; 276 FileSystemURL url = CreateURL(kITunesMediaDir); 277 bool completed = false; 278 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 279 280 ASSERT_TRUE(completed); 281 ASSERT_EQ(2u, contents.size()); 282 283 EXPECT_TRUE(contents.front().is_directory); 284 EXPECT_TRUE(contents.back().is_directory); 285 286 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesAutoAddDir).value(), 287 contents.front().name); 288 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 289 contents.back().name); 290 } 291 292 TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerate) { 293 data_provider()->SetProvideAutoAddDir(true); 294 ASSERT_EQ(0, base::WriteFile( 295 data_provider()->auto_add_path().AppendASCII("baz.ogg"), NULL, 0)); 296 297 FileSystemOperation::FileEntryList contents; 298 FileSystemURL url = CreateURL( 299 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 300 bool completed = false; 301 302 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 303 ASSERT_TRUE(completed); 304 ASSERT_EQ(1u, contents.size()); 305 EXPECT_FALSE(contents.front().is_directory); 306 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 307 contents.front().name); 308 } 309 310 TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerateNested) { 311 data_provider()->SetProvideAutoAddDir(true); 312 base::FilePath nested_dir = 313 data_provider()->auto_add_path().AppendASCII("foo").AppendASCII("bar"); 314 ASSERT_TRUE(base::CreateDirectory(nested_dir)); 315 ASSERT_EQ(0, 316 base::WriteFile(nested_dir.AppendASCII("baz.ogg"), NULL, 0)); 317 318 FileSystemOperation::FileEntryList contents; 319 FileSystemURL url = CreateURL( 320 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 321 bool completed = false; 322 323 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 324 ASSERT_TRUE(completed); 325 ASSERT_EQ(1u, contents.size()); 326 EXPECT_TRUE(contents.front().is_directory); 327 EXPECT_EQ(base::FilePath().AppendASCII("foo").value(), contents.front().name); 328 329 contents.clear(); 330 url = CreateURL( 331 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo"); 332 completed = false; 333 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 334 ASSERT_TRUE(completed); 335 ASSERT_EQ(1u, contents.size()); 336 EXPECT_TRUE(contents.front().is_directory); 337 EXPECT_EQ(base::FilePath().AppendASCII("bar").value(), contents.front().name); 338 339 contents.clear(); 340 url = CreateURL( 341 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo/bar"); 342 completed = false; 343 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 344 ASSERT_TRUE(completed); 345 ASSERT_EQ(1u, contents.size()); 346 EXPECT_FALSE(contents.front().is_directory); 347 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 348 contents.front().name); 349 } 350 351 } // namespace itunes 352