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