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/files/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 "storage/browser/fileapi/async_file_util.h" 26#include "storage/browser/fileapi/external_mount_points.h" 27#include "storage/browser/fileapi/file_system_context.h" 28#include "storage/browser/fileapi/file_system_operation_context.h" 29#include "storage/browser/fileapi/file_system_operation_runner.h" 30#include "testing/gtest/include/gtest/gtest.h" 31 32using storage::FileSystemOperationContext; 33using storage::FileSystemOperation; 34using storage::FileSystemURL; 35 36namespace itunes { 37 38namespace { 39 40void 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 52void ReadDirectoryTestHelper(storage::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 67class 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 97class 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 114class 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 storage::AsyncFileUtil* GetAsyncFileUtil( 124 storage::FileSystemType type) OVERRIDE { 125 if (type != storage::kFileSystemTypeItunes) 126 return NULL; 127 128 return test_file_util_.get(); 129 } 130 131 private: 132 scoped_ptr<storage::AsyncFileUtil> test_file_util_; 133}; 134 135class 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<storage::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<storage::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 storage::FileSystemContext( 181 base::MessageLoopProxy::current().get(), 182 base::MessageLoopProxy::current().get(), 183 storage::ExternalMountPoints::CreateRefCounted().get(), 184 storage_policy.get(), 185 NULL, 186 additional_providers.Pass(), 187 std::vector<storage::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"), 209 storage::kFileSystemTypeItunes, 210 virtual_path); 211 } 212 213 storage::FileSystemOperationRunner* operation_runner() const { 214 return file_system_context_->operation_runner(); 215 } 216 217 scoped_refptr<storage::FileSystemContext> file_system_context() const { 218 return file_system_context_; 219 } 220 221 TestITunesDataProvider* data_provider() const { 222 return itunes_data_provider_.get(); 223 } 224 225 private: 226 base::MessageLoop message_loop_; 227 content::TestBrowserThread io_thread_; 228 229 base::ScopedTempDir profile_dir_; 230 base::ScopedTempDir fake_library_dir_; 231 232 scoped_refptr<storage::FileSystemContext> file_system_context_; 233 scoped_ptr<MediaPathFilter> media_path_filter_; 234 scoped_ptr<TestITunesDataProvider> itunes_data_provider_; 235 236 DISALLOW_COPY_AND_ASSIGN(ItunesFileUtilTest); 237}; 238 239TEST_F(ItunesFileUtilTest, RootContents) { 240 FileSystemOperation::FileEntryList contents; 241 FileSystemURL url = CreateURL(""); 242 bool completed = false; 243 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 244 245 ASSERT_TRUE(completed); 246 ASSERT_EQ(2u, contents.size()); 247 248 EXPECT_FALSE(contents.front().is_directory); 249 EXPECT_TRUE(contents.back().is_directory); 250 251 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesLibraryXML).value(), 252 contents.front().name); 253 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMediaDir).value(), 254 contents.back().name); 255} 256 257TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsNoAutoAdd) { 258 data_provider()->SetProvideAutoAddDir(false); 259 260 FileSystemOperation::FileEntryList contents; 261 FileSystemURL url = CreateURL(kITunesMediaDir); 262 bool completed = false; 263 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 264 265 ASSERT_TRUE(completed); 266 ASSERT_EQ(1u, contents.size()); 267 268 EXPECT_TRUE(contents.front().is_directory); 269 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 270 contents.back().name); 271} 272 273TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsAutoAdd) { 274 data_provider()->SetProvideAutoAddDir(true); 275 276 FileSystemOperation::FileEntryList contents; 277 FileSystemURL url = CreateURL(kITunesMediaDir); 278 bool completed = false; 279 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 280 281 ASSERT_TRUE(completed); 282 ASSERT_EQ(2u, contents.size()); 283 284 EXPECT_TRUE(contents.front().is_directory); 285 EXPECT_TRUE(contents.back().is_directory); 286 287 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesAutoAddDir).value(), 288 contents.front().name); 289 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(), 290 contents.back().name); 291} 292 293TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerate) { 294 data_provider()->SetProvideAutoAddDir(true); 295 ASSERT_EQ(0, base::WriteFile( 296 data_provider()->auto_add_path().AppendASCII("baz.ogg"), NULL, 0)); 297 298 FileSystemOperation::FileEntryList contents; 299 FileSystemURL url = CreateURL( 300 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 301 bool completed = false; 302 303 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 304 ASSERT_TRUE(completed); 305 ASSERT_EQ(1u, contents.size()); 306 EXPECT_FALSE(contents.front().is_directory); 307 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 308 contents.front().name); 309} 310 311TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerateNested) { 312 data_provider()->SetProvideAutoAddDir(true); 313 base::FilePath nested_dir = 314 data_provider()->auto_add_path().AppendASCII("foo").AppendASCII("bar"); 315 ASSERT_TRUE(base::CreateDirectory(nested_dir)); 316 ASSERT_EQ(0, 317 base::WriteFile(nested_dir.AppendASCII("baz.ogg"), NULL, 0)); 318 319 FileSystemOperation::FileEntryList contents; 320 FileSystemURL url = CreateURL( 321 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir); 322 bool completed = false; 323 324 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 325 ASSERT_TRUE(completed); 326 ASSERT_EQ(1u, contents.size()); 327 EXPECT_TRUE(contents.front().is_directory); 328 EXPECT_EQ(base::FilePath().AppendASCII("foo").value(), contents.front().name); 329 330 contents.clear(); 331 url = CreateURL( 332 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo"); 333 completed = false; 334 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 335 ASSERT_TRUE(completed); 336 ASSERT_EQ(1u, contents.size()); 337 EXPECT_TRUE(contents.front().is_directory); 338 EXPECT_EQ(base::FilePath().AppendASCII("bar").value(), contents.front().name); 339 340 contents.clear(); 341 url = CreateURL( 342 std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo/bar"); 343 completed = false; 344 ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed); 345 ASSERT_TRUE(completed); 346 ASSERT_EQ(1u, contents.size()); 347 EXPECT_FALSE(contents.front().is_directory); 348 EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(), 349 contents.front().name); 350} 351 352} // namespace itunes 353