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.
5 #include "chrome/browser/extensions/extension_garbage_collector_chromeos.h"
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_chrome_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"
36 const char kExtensionId1
[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
37 const char kExtensionId2
[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
40 namespace extensions
{
42 class ExtensionGarbageCollectorChromeOSUnitTest
43 : public ExtensionServiceTestBase
{
45 const base::FilePath
& cache_dir() { return cache_dir_
.path(); }
47 void SetUp() override
{
48 #if defined(ENABLE_PLUGINS)
49 content::PluginService::GetInstance()->Init();
51 InitializeGoodInstalledExtensionService();
53 // Need real IO thread.
54 service_
->SetFileTaskRunnerForTesting(
55 content::BrowserThread::GetBlockingPool()
56 ->GetSequencedTaskRunnerWithShutdownBehavior(
57 content::BrowserThread::GetBlockingPool()
58 ->GetNamedSequenceToken("ext_install-"),
59 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
));
61 CHECK(cache_dir_
.CreateUniqueTempDir());
62 ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(cache_dir());
63 ExtensionGarbageCollectorChromeOS::ClearGarbageCollectedForTesting();
65 // Initialize the UserManager singleton to a fresh FakeChromeUserManager
67 user_manager_enabler_
.reset(new chromeos::ScopedUserManagerEnabler(
68 new chromeos::FakeChromeUserManager
));
70 GetFakeUserManager()->AddUser(chromeos::login::kStubUser
);
71 GetFakeUserManager()->LoginUser(chromeos::login::kStubUser
);
72 chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
73 GetFakeUserManager()->GetActiveUser(), profile_
.get());
76 void GarbageCollectExtensions() {
77 ExtensionGarbageCollector::Get(profile_
.get())
78 ->GarbageCollectExtensionsForTest();
79 // Wait for GarbageCollectExtensions task to complete.
80 content::RunAllBlockingPoolTasksUntilIdle();
83 base::FilePath
CreateSharedExtensionDir(const std::string
& id
,
84 const std::string
& version
,
85 const base::FilePath
& shared_dir
) {
86 base::FilePath path
= shared_dir
.AppendASCII(id
).AppendASCII(version
);
87 CreateDirectory(path
);
91 void CreateSharedExtensionPrefs(const std::string
& id
,
92 const std::string
& version
,
93 const std::string
& users_string
,
94 const base::FilePath
& path
) {
95 DictionaryPrefUpdate
shared_extensions(testing_local_state_
.Get(),
96 ExtensionAssetsManagerChromeOS::kSharedExtensions
);
98 base::DictionaryValue
* extension_info
= NULL
;
99 if (!shared_extensions
->GetDictionary(id
, &extension_info
)) {
100 extension_info
= new base::DictionaryValue
;
101 shared_extensions
->Set(id
, extension_info
);
104 base::DictionaryValue
* version_info
= new base::DictionaryValue
;
105 extension_info
->SetWithoutPathExpansion(version
, version_info
);
106 version_info
->SetString(
107 ExtensionAssetsManagerChromeOS::kSharedExtensionPath
, path
.value());
109 base::ListValue
* users
= new base::ListValue
;
110 version_info
->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers
,
112 std::vector
<std::string
> users_list
;
113 if (Tokenize(users_string
, ",", &users_list
)) {
114 for (size_t i
= 0; i
< users_list
.size(); i
++) {
115 users
->AppendString(users_list
[i
]);
120 scoped_refptr
<Extension
> CreateExtension(const std::string
& id
,
121 const std::string
& version
,
122 const base::FilePath
& path
) {
123 base::DictionaryValue manifest
;
124 manifest
.SetString(manifest_keys::kName
, "test");
125 manifest
.SetString(manifest_keys::kVersion
, version
);
128 scoped_refptr
<Extension
> extension
= Extension::Create(
129 path
, Manifest::INTERNAL
, manifest
, Extension::NO_FLAGS
, id
, &error
);
130 CHECK(extension
.get()) << error
;
131 CHECK_EQ(id
, extension
->id());
136 ExtensionPrefs
* GetExtensionPrefs() {
137 return ExtensionPrefs::Get(profile_
.get());
140 chromeos::FakeChromeUserManager
* GetFakeUserManager() {
141 return static_cast<chromeos::FakeChromeUserManager
*>(
142 user_manager::UserManager::Get());
146 scoped_ptr
<chromeos::ScopedUserManagerEnabler
> user_manager_enabler_
;
147 base::ScopedTempDir cache_dir_
;
150 // Test shared extensions clean up.
151 TEST_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
));
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::login::kStubUser
, path_id1_2
);
163 EXPECT_TRUE(base::PathExists(path_id1_2
));
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::login::kStubUser
, path_id2_1
);
170 scoped_refptr
<Extension
> extension2
= CreateExtension(kExtensionId2
, "1.0",
172 GetExtensionPrefs()->SetDelayedInstallInfo(
176 ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE
,
177 syncer::StringOrdinal(),
179 EXPECT_TRUE(base::PathExists(path_id2_1
));
181 GarbageCollectExtensions();
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
)));
187 EXPECT_TRUE(base::PathExists(path_id2_1
));
189 const base::DictionaryValue
* shared_extensions
= testing_local_state_
.Get()->
190 GetDictionary(ExtensionAssetsManagerChromeOS::kSharedExtensions
);
191 ASSERT_TRUE(shared_extensions
);
193 EXPECT_FALSE(shared_extensions
->HasKey(kExtensionId1
));
194 EXPECT_TRUE(shared_extensions
->HasKey(kExtensionId2
));
197 } // namespace extensions