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 "content/public/browser/browser_thread.h" 21 #include "content/public/test/test_browser_thread.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 #include "webkit/browser/fileapi/async_file_util_adapter.h" 24 #include "webkit/browser/fileapi/external_mount_points.h" 25 #include "webkit/browser/fileapi/file_system_context.h" 26 #include "webkit/browser/fileapi/file_system_operation_context.h" 27 #include "webkit/browser/fileapi/file_system_operation_runner.h" 28 #include "webkit/browser/fileapi/mock_file_system_options.h" 29 #include "webkit/browser/quota/mock_special_storage_policy.h" 30 31 using fileapi::FileSystemFileUtil; 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::PlatformFileError error, 44 const FileSystemOperation::FileEntryList& file_list, 45 bool has_more) { 46 DCHECK(!*completed); 47 *completed = !has_more && error == base::PLATFORM_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(chrome::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 115 : public chrome::MediaFileSystemBackend { 116 public: 117 TestMediaFileSystemBackend(const base::FilePath& profile_path, 118 ITunesFileUtil* itunes_file_util) 119 : chrome::MediaFileSystemBackend( 120 profile_path, 121 chrome::MediaFileSystemBackend::MediaTaskRunner().get()), 122 test_file_util_(itunes_file_util) {} 123 124 virtual fileapi::AsyncFileUtil* 125 GetAsyncFileUtil(fileapi::FileSystemType type) OVERRIDE { 126 if (type != fileapi::kFileSystemTypeItunes) 127 return NULL; 128 129 return test_file_util_.get(); 130 } 131 132 private: 133 scoped_ptr<fileapi::AsyncFileUtil> test_file_util_; 134 }; 135 136 class ItunesFileUtilTest : public testing::Test { 137 public: 138 ItunesFileUtilTest() 139 : io_thread_(content::BrowserThread::IO, &message_loop_) { 140 } 141 virtual ~ItunesFileUtilTest() {} 142 143 void SetUpDataProvider() { 144 ASSERT_TRUE(fake_library_dir_.CreateUniqueTempDir()); 145 ASSERT_EQ( 146 0, 147 file_util::WriteFile( 148 fake_library_dir_.path().AppendASCII(kITunesLibraryXML), 149 NULL, 150 0)); 151 152 itunes_data_provider_.reset( 153 new TestITunesDataProvider(fake_library_dir_.path())); 154 } 155 156 virtual void SetUp() OVERRIDE { 157 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); 158 159 scoped_refptr<quota::SpecialStoragePolicy> storage_policy = 160 new quota::MockSpecialStoragePolicy(); 161 162 // Initialize fake ItunesDataProvider on media task runner thread. 163 chrome::MediaFileSystemBackend::MediaTaskRunner()->PostTask( 164 FROM_HERE, 165 base::Bind(&ItunesFileUtilTest::SetUpDataProvider, 166 base::Unretained(this))); 167 base::WaitableEvent event(true, false /* initially_signalled */); 168 chrome::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 chrome::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 profile_dir_.path(), 188 fileapi::CreateAllowFileAccessOptions()); 189 } 190 191 protected: 192 void TestNonexistentFolder(const std::string& path_append) { 193 FileSystemOperation::FileEntryList contents; 194 FileSystemURL url = CreateURL(path_append); 195 bool completed = false; 196 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 197 198 ASSERT_FALSE(completed); 199 } 200 201 FileSystemURL CreateURL(const std::string& virtual_path) const { 202 return file_system_context_->CreateCrackedFileSystemURL( 203 GURL("http://www.example.com"), fileapi::kFileSystemTypeItunes, 204 base::FilePath::FromUTF8Unsafe(virtual_path)); 205 } 206 207 fileapi::FileSystemOperationRunner* operation_runner() const { 208 return file_system_context_->operation_runner(); 209 } 210 211 scoped_refptr<fileapi::FileSystemContext> file_system_context() const { 212 return file_system_context_; 213 } 214 215 TestITunesDataProvider* data_provider() const { 216 return itunes_data_provider_.get(); 217 } 218 219 private: 220 base::MessageLoop message_loop_; 221 content::TestBrowserThread io_thread_; 222 223 base::ScopedTempDir profile_dir_; 224 base::ScopedTempDir fake_library_dir_; 225 226 scoped_refptr<fileapi::FileSystemContext> file_system_context_; 227 scoped_ptr<chrome::MediaPathFilter> media_path_filter_; 228 scoped_ptr<TestITunesDataProvider> itunes_data_provider_; 229 230 DISALLOW_COPY_AND_ASSIGN(ItunesFileUtilTest); 231 }; 232 233 TEST_F(ItunesFileUtilTest, RootContents) { 234 FileSystemOperation::FileEntryList contents; 235 FileSystemURL url = CreateURL(""); 236 bool completed = false; 237 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 238 239 ASSERT_TRUE(completed); 240 ASSERT_EQ(2u, contents.size()); 241 242 EXPECT_FALSE(contents.front().is_directory); 243 EXPECT_TRUE(contents.back().is_directory); 244 245 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesLibraryXML).value(), 246 contents.front().name); 247 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMediaDir).value(), 248 contents.back().name); 249 } 250 251 TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsNoAutoAdd) { 252 data_provider()->SetProvideAutoAddDir(false); 253 254 FileSystemOperation::FileEntryList contents; 255 FileSystemURL url = CreateURL(kITunesMediaDir); 256 bool completed = false; 257 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 258 259 ASSERT_TRUE(completed); 260 ASSERT_EQ(1u, contents.size()); 261 262 EXPECT_TRUE(contents.front().is_directory); 263 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 264 contents.back().name); 265 } 266 267 TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsAutoAdd) { 268 data_provider()->SetProvideAutoAddDir(true); 269 270 FileSystemOperation::FileEntryList contents; 271 FileSystemURL url = CreateURL(kITunesMediaDir); 272 bool completed = false; 273 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 274 275 ASSERT_TRUE(completed); 276 ASSERT_EQ(2u, contents.size()); 277 278 EXPECT_TRUE(contents.front().is_directory); 279 EXPECT_TRUE(contents.back().is_directory); 280 281 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesAutoAddDir).value(), 282 contents.front().name); 283 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 284 contents.back().name); 285 } 286 287 TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerate) { 288 data_provider()->SetProvideAutoAddDir(true); 289 ASSERT_EQ(0, file_util::WriteFile( 290 data_provider()->auto_add_path().AppendASCII("baz.ogg"), NULL, 0)); 291 292 FileSystemOperation::FileEntryList contents; 293 FileSystemURL url = CreateURL( 294 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 295 bool completed = false; 296 297 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 298 ASSERT_TRUE(completed); 299 ASSERT_EQ(1u, contents.size()); 300 EXPECT_FALSE(contents.front().is_directory); 301 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 302 contents.front().name); 303 } 304 305 TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerateNested) { 306 data_provider()->SetProvideAutoAddDir(true); 307 base::FilePath nested_dir = 308 data_provider()->auto_add_path().AppendASCII("foo").AppendASCII("bar"); 309 ASSERT_TRUE(file_util::CreateDirectory(nested_dir)); 310 ASSERT_EQ(0, 311 file_util::WriteFile(nested_dir.AppendASCII("baz.ogg"), NULL, 0)); 312 313 FileSystemOperation::FileEntryList contents; 314 FileSystemURL url = CreateURL( 315 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 316 bool completed = false; 317 318 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 319 ASSERT_TRUE(completed); 320 ASSERT_EQ(1u, contents.size()); 321 EXPECT_TRUE(contents.front().is_directory); 322 EXPECT_EQ(base::FilePath().AppendASCII("foo").value(), contents.front().name); 323 324 contents.clear(); 325 url = CreateURL( 326 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo"); 327 completed = false; 328 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 329 ASSERT_TRUE(completed); 330 ASSERT_EQ(1u, contents.size()); 331 EXPECT_TRUE(contents.front().is_directory); 332 EXPECT_EQ(base::FilePath().AppendASCII("bar").value(), contents.front().name); 333 334 contents.clear(); 335 url = CreateURL( 336 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo/bar"); 337 completed = false; 338 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 339 ASSERT_TRUE(completed); 340 ASSERT_EQ(1u, contents.size()); 341 EXPECT_FALSE(contents.front().is_directory); 342 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 343 contents.front().name); 344 } 345 346 } // namespace itunes 347