Home | History | Annotate | Download | only in file_system_provider
      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 #include <vector>
      7 
      8 #include "base/files/file.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
     13 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
     14 #include "chrome/browser/chromeos/file_system_provider/observer.h"
     15 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
     16 #include "chrome/browser/chromeos/file_system_provider/service.h"
     17 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "chrome/test/base/testing_pref_service_syncable.h"
     20 #include "chrome/test/base/testing_profile.h"
     21 #include "components/user_prefs/user_prefs.h"
     22 #include "content/public/test/test_browser_thread_bundle.h"
     23 #include "extensions/browser/extension_registry.h"
     24 #include "extensions/common/extension.h"
     25 #include "extensions/common/manifest_constants.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 #include "webkit/browser/fileapi/external_mount_points.h"
     28 
     29 namespace chromeos {
     30 namespace file_system_provider {
     31 namespace {
     32 
     33 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
     34 const char kFileSystemId[] = "camera/pictures/id !@#$%^&*()_+";
     35 const char kFileSystemName[] = "Camera Pictures";
     36 
     37 // Utility observer, logging events from file_system_provider::Service.
     38 class LoggingObserver : public Observer {
     39  public:
     40   class Event {
     41    public:
     42     Event(const ProvidedFileSystemInfo& file_system_info,
     43           base::File::Error error)
     44         : file_system_info_(file_system_info), error_(error) {}
     45     ~Event() {}
     46 
     47     const ProvidedFileSystemInfo& file_system_info() {
     48       return file_system_info_;
     49     }
     50     base::File::Error error() { return error_; }
     51 
     52    private:
     53     ProvidedFileSystemInfo file_system_info_;
     54     base::File::Error error_;
     55   };
     56 
     57   LoggingObserver() {}
     58   virtual ~LoggingObserver() {}
     59 
     60   // file_system_provider::Observer overrides.
     61   virtual void OnProvidedFileSystemMount(
     62       const ProvidedFileSystemInfo& file_system_info,
     63       base::File::Error error) OVERRIDE {
     64     mounts.push_back(Event(file_system_info, error));
     65   }
     66 
     67   virtual void OnProvidedFileSystemUnmount(
     68       const ProvidedFileSystemInfo& file_system_info,
     69       base::File::Error error) OVERRIDE {
     70     unmounts.push_back(Event(file_system_info, error));
     71   }
     72 
     73   std::vector<Event> mounts;
     74   std::vector<Event> unmounts;
     75 };
     76 
     77 // Creates a fake extension with the specified |extension_id|.
     78 scoped_refptr<extensions::Extension> createFakeExtension(
     79     const std::string& extension_id) {
     80   base::DictionaryValue manifest;
     81   std::string error;
     82   manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
     83   manifest.SetString(extensions::manifest_keys::kName, "unused");
     84   return extensions::Extension::Create(base::FilePath(),
     85                                        extensions::Manifest::UNPACKED,
     86                                        manifest,
     87                                        extensions::Extension::NO_FLAGS,
     88                                        extension_id,
     89                                        &error);
     90 }
     91 
     92 // Stores a provided file system information in preferences.
     93 void RememberFakeFileSystem(TestingProfile* profile,
     94                             const std::string& extension_id,
     95                             const std::string& file_system_id,
     96                             const std::string& file_system_name) {
     97   TestingPrefServiceSyncable* pref_service = profile->GetTestingPrefService();
     98   ASSERT_TRUE(pref_service);
     99 
    100   base::DictionaryValue extensions;
    101   base::ListValue* file_systems = new base::ListValue();
    102   base::DictionaryValue* file_system = new base::DictionaryValue();
    103   file_system->SetString(kPrefKeyFileSystemId, kFileSystemId);
    104   file_system->SetString(kPrefKeyFileSystemName, kFileSystemName);
    105   file_systems->Append(file_system);
    106   extensions.Set(kExtensionId, file_systems);
    107 
    108   pref_service->Set(prefs::kFileSystemProviderMounted, extensions);
    109 }
    110 
    111 }  // namespace
    112 
    113 class FileSystemProviderServiceTest : public testing::Test {
    114  protected:
    115   FileSystemProviderServiceTest() {}
    116   virtual ~FileSystemProviderServiceTest() {}
    117 
    118   virtual void SetUp() OVERRIDE {
    119     profile_.reset(new TestingProfile);
    120     user_manager_ = new FakeUserManager();
    121     user_manager_->AddUser(profile_->GetProfileName());
    122     user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
    123     extension_registry_.reset(
    124         new extensions::ExtensionRegistry(profile_.get()));
    125     file_system_provider_service_.reset(
    126         new Service(profile_.get(), extension_registry_.get()));
    127     file_system_provider_service_->SetFileSystemFactoryForTesting(
    128         base::Bind(&FakeProvidedFileSystem::Create));
    129     extension_ = createFakeExtension(kExtensionId);
    130   }
    131 
    132   content::TestBrowserThreadBundle thread_bundle_;
    133   scoped_ptr<TestingProfile> profile_;
    134   FakeUserManager* user_manager_;
    135   scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
    136   scoped_ptr<extensions::ExtensionRegistry> extension_registry_;
    137   scoped_ptr<Service> file_system_provider_service_;
    138   scoped_refptr<extensions::Extension> extension_;
    139 };
    140 
    141 TEST_F(FileSystemProviderServiceTest, MountFileSystem) {
    142   LoggingObserver observer;
    143   file_system_provider_service_->AddObserver(&observer);
    144 
    145   const bool result = file_system_provider_service_->MountFileSystem(
    146       kExtensionId, kFileSystemId, kFileSystemName);
    147   EXPECT_TRUE(result);
    148 
    149   ASSERT_EQ(1u, observer.mounts.size());
    150   EXPECT_EQ(kExtensionId, observer.mounts[0].file_system_info().extension_id());
    151   EXPECT_EQ(kFileSystemId,
    152             observer.mounts[0].file_system_info().file_system_id());
    153   base::FilePath expected_mount_path =
    154       util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
    155   EXPECT_EQ(expected_mount_path.AsUTF8Unsafe(),
    156             observer.mounts[0].file_system_info().mount_path().AsUTF8Unsafe());
    157   EXPECT_EQ(kFileSystemName,
    158             observer.mounts[0].file_system_info().file_system_name());
    159   EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
    160   ASSERT_EQ(0u, observer.unmounts.size());
    161 
    162   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    163       file_system_provider_service_->GetProvidedFileSystemInfoList();
    164   ASSERT_EQ(1u, file_system_info_list.size());
    165 
    166   file_system_provider_service_->RemoveObserver(&observer);
    167 }
    168 
    169 TEST_F(FileSystemProviderServiceTest, MountFileSystem_UniqueIds) {
    170   LoggingObserver observer;
    171   file_system_provider_service_->AddObserver(&observer);
    172 
    173   const bool result = file_system_provider_service_->MountFileSystem(
    174       kExtensionId, kFileSystemId, kFileSystemName);
    175   EXPECT_TRUE(result);
    176 
    177   const bool second_result = file_system_provider_service_->MountFileSystem(
    178       kExtensionId, kFileSystemId, kFileSystemName);
    179   EXPECT_FALSE(second_result);
    180 
    181   ASSERT_EQ(2u, observer.mounts.size());
    182   EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
    183   EXPECT_EQ(base::File::FILE_ERROR_EXISTS, observer.mounts[1].error());
    184 
    185   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    186       file_system_provider_service_->GetProvidedFileSystemInfoList();
    187   ASSERT_EQ(1u, file_system_info_list.size());
    188 
    189   file_system_provider_service_->RemoveObserver(&observer);
    190 }
    191 
    192 TEST_F(FileSystemProviderServiceTest, MountFileSystem_StressTest) {
    193   LoggingObserver observer;
    194   file_system_provider_service_->AddObserver(&observer);
    195 
    196   const size_t kMaxFileSystems = 16;
    197   for (size_t i = 0; i < kMaxFileSystems; ++i) {
    198     const std::string file_system_id =
    199         std::string("test-") + base::IntToString(i);
    200     const bool result = file_system_provider_service_->MountFileSystem(
    201         kExtensionId, file_system_id, kFileSystemName);
    202     EXPECT_TRUE(result);
    203   }
    204   ASSERT_EQ(kMaxFileSystems, observer.mounts.size());
    205 
    206   // The next file system is out of limit, and registering it should fail.
    207   const bool result = file_system_provider_service_->MountFileSystem(
    208       kExtensionId, kFileSystemId, kFileSystemName);
    209   EXPECT_FALSE(result);
    210 
    211   ASSERT_EQ(kMaxFileSystems + 1, observer.mounts.size());
    212   EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED,
    213             observer.mounts[kMaxFileSystems].error());
    214 
    215   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    216       file_system_provider_service_->GetProvidedFileSystemInfoList();
    217   ASSERT_EQ(kMaxFileSystems, file_system_info_list.size());
    218 
    219   file_system_provider_service_->RemoveObserver(&observer);
    220 }
    221 
    222 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem) {
    223   LoggingObserver observer;
    224   file_system_provider_service_->AddObserver(&observer);
    225 
    226   const bool result = file_system_provider_service_->MountFileSystem(
    227       kExtensionId, kFileSystemId, kFileSystemName);
    228   EXPECT_TRUE(result);
    229   ASSERT_EQ(1u, observer.mounts.size());
    230 
    231   const bool unmount_result = file_system_provider_service_->UnmountFileSystem(
    232       kExtensionId, kFileSystemId);
    233   EXPECT_TRUE(unmount_result);
    234   ASSERT_EQ(1u, observer.unmounts.size());
    235   EXPECT_EQ(base::File::FILE_OK, observer.unmounts[0].error());
    236 
    237   EXPECT_EQ(kExtensionId,
    238             observer.unmounts[0].file_system_info().extension_id());
    239   EXPECT_EQ(kFileSystemId,
    240             observer.unmounts[0].file_system_info().file_system_id());
    241 
    242   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    243       file_system_provider_service_->GetProvidedFileSystemInfoList();
    244   ASSERT_EQ(0u, file_system_info_list.size());
    245 
    246   file_system_provider_service_->RemoveObserver(&observer);
    247 }
    248 
    249 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem_OnExtensionUnload) {
    250   LoggingObserver observer;
    251   file_system_provider_service_->AddObserver(&observer);
    252 
    253   const bool result = file_system_provider_service_->MountFileSystem(
    254       kExtensionId, kFileSystemId, kFileSystemName);
    255   EXPECT_TRUE(result);
    256   ASSERT_EQ(1u, observer.mounts.size());
    257 
    258   // Directly call the observer's method.
    259   file_system_provider_service_->OnExtensionUnloaded(
    260       profile_.get(),
    261       extension_.get(),
    262       extensions::UnloadedExtensionInfo::REASON_DISABLE);
    263 
    264   ASSERT_EQ(1u, observer.unmounts.size());
    265   EXPECT_EQ(base::File::FILE_OK, observer.unmounts[0].error());
    266 
    267   EXPECT_EQ(kExtensionId,
    268             observer.unmounts[0].file_system_info().extension_id());
    269   EXPECT_EQ(kFileSystemId,
    270             observer.unmounts[0].file_system_info().file_system_id());
    271 
    272   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    273       file_system_provider_service_->GetProvidedFileSystemInfoList();
    274   ASSERT_EQ(0u, file_system_info_list.size());
    275 
    276   file_system_provider_service_->RemoveObserver(&observer);
    277 }
    278 
    279 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem_WrongExtensionId) {
    280   LoggingObserver observer;
    281   file_system_provider_service_->AddObserver(&observer);
    282 
    283   const std::string kWrongExtensionId = "helloworldhelloworldhelloworldhe";
    284 
    285   const bool result = file_system_provider_service_->MountFileSystem(
    286       kExtensionId, kFileSystemId, kFileSystemName);
    287   EXPECT_TRUE(result);
    288   ASSERT_EQ(1u, observer.mounts.size());
    289   ASSERT_EQ(
    290       1u,
    291       file_system_provider_service_->GetProvidedFileSystemInfoList().size());
    292 
    293   const bool unmount_result = file_system_provider_service_->UnmountFileSystem(
    294       kWrongExtensionId, kFileSystemId);
    295   EXPECT_FALSE(unmount_result);
    296   ASSERT_EQ(1u, observer.unmounts.size());
    297   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, observer.unmounts[0].error());
    298   ASSERT_EQ(
    299       1u,
    300       file_system_provider_service_->GetProvidedFileSystemInfoList().size());
    301 
    302   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    303       file_system_provider_service_->GetProvidedFileSystemInfoList();
    304   ASSERT_EQ(1u, file_system_info_list.size());
    305 
    306   file_system_provider_service_->RemoveObserver(&observer);
    307 }
    308 
    309 TEST_F(FileSystemProviderServiceTest, RestoreFileSystem_OnExtensionLoad) {
    310   LoggingObserver observer;
    311   file_system_provider_service_->AddObserver(&observer);
    312 
    313   // Create a fake entry in the preferences.
    314   RememberFakeFileSystem(
    315       profile_.get(), kExtensionId, kFileSystemId, kFileSystemName);
    316 
    317   EXPECT_EQ(0u, observer.mounts.size());
    318 
    319   // Directly call the observer's method.
    320   file_system_provider_service_->OnExtensionLoaded(profile_.get(),
    321                                                    extension_.get());
    322 
    323   ASSERT_EQ(1u, observer.mounts.size());
    324   EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
    325 
    326   EXPECT_EQ(kExtensionId, observer.mounts[0].file_system_info().extension_id());
    327   EXPECT_EQ(kFileSystemId,
    328             observer.mounts[0].file_system_info().file_system_id());
    329 
    330   std::vector<ProvidedFileSystemInfo> file_system_info_list =
    331       file_system_provider_service_->GetProvidedFileSystemInfoList();
    332   ASSERT_EQ(1u, file_system_info_list.size());
    333 
    334   file_system_provider_service_->RemoveObserver(&observer);
    335 }
    336 
    337 TEST_F(FileSystemProviderServiceTest, ForgetFileSystem_OnExtensionUnload) {
    338   LoggingObserver observer;
    339   file_system_provider_service_->AddObserver(&observer);
    340 
    341   // Create a fake entry in the preferences.
    342   RememberFakeFileSystem(
    343       profile_.get(), kExtensionId, kFileSystemId, kFileSystemName);
    344 
    345   // Directly call the observer's methods.
    346   file_system_provider_service_->OnExtensionLoaded(profile_.get(),
    347                                                    extension_.get());
    348 
    349   file_system_provider_service_->OnExtensionUnloaded(
    350       profile_.get(),
    351       extension_.get(),
    352       extensions::UnloadedExtensionInfo::REASON_DISABLE);
    353 
    354   ASSERT_EQ(1u, observer.mounts.size());
    355   EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
    356   ASSERT_EQ(1u, observer.unmounts.size());
    357   EXPECT_EQ(base::File::FILE_OK, observer.unmounts[0].error());
    358 
    359   TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
    360   ASSERT_TRUE(pref_service);
    361 
    362   const base::DictionaryValue* extensions =
    363       pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
    364   ASSERT_TRUE(extensions);
    365 
    366   const base::ListValue* file_systems;
    367   EXPECT_FALSE(extensions->GetList(kExtensionId, &file_systems));
    368 
    369   file_system_provider_service_->RemoveObserver(&observer);
    370 }
    371 
    372 TEST_F(FileSystemProviderServiceTest, RememberFileSystem_OnShutdown) {
    373   {
    374     scoped_ptr<Service> service(
    375         new Service(profile_.get(), extension_registry_.get()));
    376     service->SetFileSystemFactoryForTesting(
    377         base::Bind(&FakeProvidedFileSystem::Create));
    378 
    379     LoggingObserver observer;
    380     service->AddObserver(&observer);
    381 
    382     const bool result =
    383         service->MountFileSystem(kExtensionId, kFileSystemId, kFileSystemName);
    384     EXPECT_TRUE(result);
    385     ASSERT_EQ(1u, observer.mounts.size());
    386 
    387     service->RemoveObserver(&observer);
    388   }
    389 
    390   TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
    391   ASSERT_TRUE(pref_service);
    392 
    393   const base::DictionaryValue* extensions =
    394       pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
    395   ASSERT_TRUE(extensions);
    396 
    397   const base::ListValue* file_systems;
    398   ASSERT_TRUE(extensions->GetList(kExtensionId, &file_systems));
    399   ASSERT_EQ(1u, file_systems->GetSize());
    400 
    401   const base::DictionaryValue* file_system = NULL;
    402   ASSERT_TRUE(file_systems->GetDictionary(0, &file_system));
    403 
    404   std::string file_system_id;
    405   file_system->GetString(kPrefKeyFileSystemId, &file_system_id);
    406   EXPECT_EQ(kFileSystemId, file_system_id);
    407 
    408   std::string file_system_name;
    409   file_system->GetString(kPrefKeyFileSystemName, &file_system_name);
    410   EXPECT_EQ(kFileSystemName, file_system_name);
    411 }
    412 
    413 }  // namespace file_system_provider
    414 }  // namespace chromeos
    415