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_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "base/values.h"
17 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
18 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
19 #include "chrome/browser/chromeos/profiles/profile_helper.h"
20 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/extension_service_test_base.h"
23 #include "chrome/browser/prefs/browser_prefs.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/test/base/testing_browser_process.h"
26 #include "chrome/test/base/testing_profile.h"
27 #include "chromeos/login/user_names.h"
28 #include "components/user_manager/user_manager.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/plugin_service.h"
31 #include "content/public/test/test_utils.h"
32 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/install_flag.h"
34 #include "extensions/common/manifest_constants.h"
37 const char kExtensionId1
[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
38 const char kExtensionId2
[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
41 namespace extensions
{
43 class ExtensionGarbageCollectorChromeOSUnitTest
44 : public ExtensionServiceTestBase
{
46 const base::FilePath
& cache_dir() { return cache_dir_
.path(); }
48 void SetUp() override
{
49 #if defined(ENABLE_PLUGINS)
50 content::PluginService::GetInstance()->Init();
52 InitializeGoodInstalledExtensionService();
54 // Need real IO thread.
55 service_
->SetFileTaskRunnerForTesting(
56 content::BrowserThread::GetBlockingPool()
57 ->GetSequencedTaskRunnerWithShutdownBehavior(
58 content::BrowserThread::GetBlockingPool()
59 ->GetNamedSequenceToken("ext_install-"),
60 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
));
62 CHECK(cache_dir_
.CreateUniqueTempDir());
63 ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(cache_dir());
64 ExtensionGarbageCollectorChromeOS::ClearGarbageCollectedForTesting();
66 // Initialize the UserManager singleton to a fresh FakeChromeUserManager
68 user_manager_enabler_
.reset(new chromeos::ScopedUserManagerEnabler(
69 new chromeos::FakeChromeUserManager
));
71 GetFakeUserManager()->AddUser(chromeos::login::kStubUser
);
72 GetFakeUserManager()->LoginUser(chromeos::login::kStubUser
);
73 chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
74 GetFakeUserManager()->GetActiveUser(), profile_
.get());
77 void GarbageCollectExtensions() {
78 ExtensionGarbageCollector::Get(profile_
.get())
79 ->GarbageCollectExtensionsForTest();
80 // Wait for GarbageCollectExtensions task to complete.
81 content::RunAllBlockingPoolTasksUntilIdle();
84 base::FilePath
CreateSharedExtensionDir(const std::string
& id
,
85 const std::string
& version
,
86 const base::FilePath
& shared_dir
) {
87 base::FilePath path
= shared_dir
.AppendASCII(id
).AppendASCII(version
);
88 CreateDirectory(path
);
92 void CreateSharedExtensionPrefs(const std::string
& id
,
93 const std::string
& version
,
94 const std::string
& users_string
,
95 const base::FilePath
& path
) {
96 DictionaryPrefUpdate
shared_extensions(testing_local_state_
.Get(),
97 ExtensionAssetsManagerChromeOS::kSharedExtensions
);
99 base::DictionaryValue
* extension_info
= NULL
;
100 if (!shared_extensions
->GetDictionary(id
, &extension_info
)) {
101 extension_info
= new base::DictionaryValue
;
102 shared_extensions
->Set(id
, extension_info
);
105 base::DictionaryValue
* version_info
= new base::DictionaryValue
;
106 extension_info
->SetWithoutPathExpansion(version
, version_info
);
107 version_info
->SetString(
108 ExtensionAssetsManagerChromeOS::kSharedExtensionPath
, path
.value());
110 base::ListValue
* users
= new base::ListValue
;
111 version_info
->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers
,
113 for (const std::string
& user
:
114 base::SplitString(users_string
, ",",
115 base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
))
116 users
->AppendString(user
);
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
);
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());
135 ExtensionPrefs
* GetExtensionPrefs() {
136 return ExtensionPrefs::Get(profile_
.get());
139 chromeos::FakeChromeUserManager
* GetFakeUserManager() {
140 return static_cast<chromeos::FakeChromeUserManager
*>(
141 user_manager::UserManager::Get());
145 scoped_ptr
<chromeos::ScopedUserManagerEnabler
> user_manager_enabler_
;
146 base::ScopedTempDir cache_dir_
;
149 // Test shared extensions clean up.
150 TEST_F(ExtensionGarbageCollectorChromeOSUnitTest
, SharedExtensions
) {
151 // Version for non-existing user.
152 base::FilePath path_id1_1
= CreateSharedExtensionDir(
153 kExtensionId1
, "1.0", cache_dir());
154 CreateSharedExtensionPrefs(kExtensionId1
, "1.0", "test@test.com", path_id1_1
);
155 EXPECT_TRUE(base::PathExists(path_id1_1
));
157 // Version for current user but the extension is not installed.
158 base::FilePath path_id1_2
= CreateSharedExtensionDir(
159 kExtensionId1
, "2.0", cache_dir());
160 CreateSharedExtensionPrefs(
161 kExtensionId1
, "2.0", chromeos::login::kStubUser
, path_id1_2
);
162 EXPECT_TRUE(base::PathExists(path_id1_2
));
164 // Version for current user that delayed install.
165 base::FilePath path_id2_1
= CreateSharedExtensionDir(
166 kExtensionId2
, "1.0", cache_dir());
167 CreateSharedExtensionPrefs(
168 kExtensionId2
, "1.0", chromeos::login::kStubUser
, path_id2_1
);
169 scoped_refptr
<Extension
> extension2
= CreateExtension(kExtensionId2
, "1.0",
171 GetExtensionPrefs()->SetDelayedInstallInfo(
175 ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE
,
176 syncer::StringOrdinal(),
178 EXPECT_TRUE(base::PathExists(path_id2_1
));
180 GarbageCollectExtensions();
182 EXPECT_FALSE(base::PathExists(path_id1_1
));
183 EXPECT_FALSE(base::PathExists(path_id1_2
));
184 EXPECT_FALSE(base::PathExists(cache_dir().AppendASCII(kExtensionId1
)));
186 EXPECT_TRUE(base::PathExists(path_id2_1
));
188 const base::DictionaryValue
* shared_extensions
= testing_local_state_
.Get()->
189 GetDictionary(ExtensionAssetsManagerChromeOS::kSharedExtensions
);
190 ASSERT_TRUE(shared_extensions
);
192 EXPECT_FALSE(shared_extensions
->HasKey(kExtensionId1
));
193 EXPECT_TRUE(shared_extensions
->HasKey(kExtensionId2
));
196 } // namespace extensions