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