Home | History | Annotate | Download | only in extensions
      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 "chrome/browser/extensions/extension_garbage_collector_chromeos.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/files/file_util.h"
     11 #include "base/prefs/scoped_user_pref_update.h"
     12 #include "base/prefs/testing_pref_service.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/threading/sequenced_worker_pool.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
     17 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
     18 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     19 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/extensions/extension_service_test_base.h"
     22 #include "chrome/browser/prefs/browser_prefs.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/test/base/testing_browser_process.h"
     25 #include "chrome/test/base/testing_profile.h"
     26 #include "chromeos/login/user_names.h"
     27 #include "components/user_manager/user_manager.h"
     28 #include "content/public/browser/browser_thread.h"
     29 #include "content/public/browser/plugin_service.h"
     30 #include "content/public/test/test_utils.h"
     31 #include "extensions/browser/extension_prefs.h"
     32 #include "extensions/browser/install_flag.h"
     33 #include "extensions/common/manifest_constants.h"
     34 
     35 namespace {
     36 const char kExtensionId1[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
     37 const char kExtensionId2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
     38 }  // namespace
     39 
     40 namespace extensions {
     41 
     42 class ExtensionGarbageCollectorChromeOSUnitTest
     43     : public ExtensionServiceTestBase {
     44  protected:
     45   PrefService& local_state() { return local_state_; }
     46   const base::FilePath& cache_dir() { return cache_dir_.path(); }
     47 
     48   virtual void SetUp() OVERRIDE {
     49     TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
     50     chrome::RegisterLocalState(local_state_.registry());
     51 
     52 #if defined(ENABLE_PLUGINS)
     53     content::PluginService::GetInstance()->Init();
     54 #endif
     55     InitializeGoodInstalledExtensionService();
     56 
     57     // Need real IO thread.
     58     service_->SetFileTaskRunnerForTesting(
     59         content::BrowserThread::GetBlockingPool()
     60             ->GetSequencedTaskRunnerWithShutdownBehavior(
     61                 content::BrowserThread::GetBlockingPool()
     62                     ->GetNamedSequenceToken("ext_install-"),
     63                 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
     64 
     65     CHECK(cache_dir_.CreateUniqueTempDir());
     66     ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(cache_dir());
     67     ExtensionGarbageCollectorChromeOS::ClearGarbageCollectedForTesting();
     68 
     69     // Initialize the UserManager singleton to a fresh FakeUserManager instance.
     70     user_manager_enabler_.reset(
     71         new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
     72 
     73     GetFakeUserManager()->AddUser(chromeos::login::kStubUser);
     74     GetFakeUserManager()->LoginUser(chromeos::login::kStubUser);
     75     chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
     76         GetFakeUserManager()->GetActiveUser(), profile_.get());
     77   }
     78 
     79   virtual void TearDown() OVERRIDE {
     80     TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
     81   }
     82 
     83   void GarbageCollectExtensions() {
     84     ExtensionGarbageCollector::Get(profile_.get())
     85         ->GarbageCollectExtensionsForTest();
     86     // Wait for GarbageCollectExtensions task to complete.
     87     content::RunAllBlockingPoolTasksUntilIdle();
     88   }
     89 
     90   base::FilePath CreateSharedExtensionDir(const std::string& id,
     91                                           const std::string& version,
     92                                           const base::FilePath& shared_dir) {
     93     base::FilePath path = shared_dir.AppendASCII(id).AppendASCII(version);
     94     CreateDirectory(path);
     95     return path;
     96   }
     97 
     98   void CreateSharedExtensionPrefs(const std::string& id,
     99                                   const std::string& version,
    100                                   const std::string& users_string,
    101                                   const base::FilePath& path) {
    102     DictionaryPrefUpdate shared_extensions(&local_state_,
    103         ExtensionAssetsManagerChromeOS::kSharedExtensions);
    104 
    105     base::DictionaryValue* extension_info = NULL;
    106     if (!shared_extensions->GetDictionary(id, &extension_info)) {
    107       extension_info = new base::DictionaryValue;
    108       shared_extensions->Set(id, extension_info);
    109     }
    110 
    111     base::DictionaryValue* version_info = new base::DictionaryValue;
    112     extension_info->SetWithoutPathExpansion(version, version_info);
    113     version_info->SetString(
    114         ExtensionAssetsManagerChromeOS::kSharedExtensionPath, path.value());
    115 
    116     base::ListValue* users = new base::ListValue;
    117     version_info->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers,
    118                       users);
    119     std::vector<std::string> users_list;
    120     if (Tokenize(users_string, ",", &users_list)) {
    121       for (size_t i = 0; i < users_list.size(); i++) {
    122         users->AppendString(users_list[i]);
    123       }
    124     }
    125   }
    126 
    127   scoped_refptr<Extension> CreateExtension(const std::string& id,
    128                                            const std::string& version,
    129                                            const base::FilePath& path) {
    130     base::DictionaryValue manifest;
    131     manifest.SetString(manifest_keys::kName, "test");
    132     manifest.SetString(manifest_keys::kVersion, version);
    133 
    134     std::string error;
    135     scoped_refptr<Extension> extension = Extension::Create(
    136         path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id, &error);
    137     CHECK(extension.get()) << error;
    138     CHECK_EQ(id, extension->id());
    139 
    140     return extension;
    141   }
    142 
    143   ExtensionPrefs* GetExtensionPrefs() {
    144     return ExtensionPrefs::Get(profile_.get());
    145   }
    146 
    147   chromeos::FakeUserManager* GetFakeUserManager() {
    148     return static_cast<chromeos::FakeUserManager*>(
    149         user_manager::UserManager::Get());
    150   }
    151 
    152  private:
    153   scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
    154   TestingPrefServiceSimple local_state_;
    155   base::ScopedTempDir cache_dir_;
    156 };
    157 
    158 // Test shared extensions clean up.
    159 TEST_F(ExtensionGarbageCollectorChromeOSUnitTest, SharedExtensions) {
    160   // Version for non-existing user.
    161   base::FilePath path_id1_1 = CreateSharedExtensionDir(
    162       kExtensionId1, "1.0", cache_dir());
    163   CreateSharedExtensionPrefs(kExtensionId1, "1.0", "test (at) test.com", path_id1_1);
    164   EXPECT_TRUE(base::PathExists(path_id1_1));
    165 
    166   // Version for current user but the extension is not installed.
    167   base::FilePath path_id1_2 = CreateSharedExtensionDir(
    168       kExtensionId1, "2.0", cache_dir());
    169   CreateSharedExtensionPrefs(
    170       kExtensionId1, "2.0", chromeos::login::kStubUser, path_id1_2);
    171   EXPECT_TRUE(base::PathExists(path_id1_2));
    172 
    173   // Version for current user that delayed install.
    174   base::FilePath path_id2_1 = CreateSharedExtensionDir(
    175       kExtensionId2, "1.0", cache_dir());
    176   CreateSharedExtensionPrefs(
    177       kExtensionId2, "1.0", chromeos::login::kStubUser, path_id2_1);
    178   scoped_refptr<Extension> extension2 = CreateExtension(kExtensionId2, "1.0",
    179                                                         path_id2_1);
    180   GetExtensionPrefs()->SetDelayedInstallInfo(
    181       extension2.get(),
    182       Extension::ENABLED,
    183       kInstallFlagNone,
    184       ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
    185       syncer::StringOrdinal(),
    186       std::string());
    187   EXPECT_TRUE(base::PathExists(path_id2_1));
    188 
    189   GarbageCollectExtensions();
    190 
    191   EXPECT_FALSE(base::PathExists(path_id1_1));
    192   EXPECT_FALSE(base::PathExists(path_id1_2));
    193   EXPECT_FALSE(base::PathExists(cache_dir().AppendASCII(kExtensionId1)));
    194 
    195   EXPECT_TRUE(base::PathExists(path_id2_1));
    196 
    197   const base::DictionaryValue* shared_extensions = local_state().GetDictionary(
    198       ExtensionAssetsManagerChromeOS::kSharedExtensions);
    199   ASSERT_TRUE(shared_extensions);
    200 
    201   EXPECT_FALSE(shared_extensions->HasKey(kExtensionId1));
    202   EXPECT_TRUE(shared_extensions->HasKey(kExtensionId2));
    203 }
    204 
    205 }  // namespace extensions
    206