blob: d73ecab56fcdb17a62f7b09f362172c4877b2533 [file] [log] [blame]
xiyuanf6a4c6a62016-04-19 18:14:541// Copyright 2016 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/update_install_gate.h"
6
7#include <memory>
8
Sylvain Defresne711ff6b2018-10-04 12:33:549#include "base/bind.h"
xiyuanf6a4c6a62016-04-19 18:14:5410#include "base/command_line.h"
11#include "base/memory/ptr_util.h"
12#include "base/run_loop.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/extensions/test_extension_system.h"
15#include "chrome/test/base/testing_browser_process.h"
16#include "chrome/test/base/testing_profile.h"
17#include "chrome/test/base/testing_profile_manager.h"
Gabriel Charettec7108742019-08-23 03:31:4018#include "content/public/test/browser_task_environment.h"
xiyuanf6a4c6a62016-04-19 18:14:5419#include "content/public/test/test_renderer_host.h"
20#include "extensions/browser/event_router.h"
21#include "extensions/browser/event_router_factory.h"
22#include "extensions/browser/extension_host.h"
23#include "extensions/browser/extension_prefs.h"
24#include "extensions/browser/extension_registry.h"
25#include "extensions/common/extension_builder.h"
26#include "extensions/common/manifest_handlers/background_info.h"
27#include "extensions/common/value_builder.h"
28#include "testing/gtest/include/gtest/gtest.h"
29
30#if defined(OS_CHROMEOS)
31#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
xiyuanf6a4c6a62016-04-19 18:14:5432#include "chrome/browser/chromeos/settings/cros_settings.h"
33#include "chrome/browser/chromeos/settings/device_settings_service.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2634#include "components/user_manager/scoped_user_manager.h"
xiyuanf6a4c6a62016-04-19 18:14:5435#endif
36
37namespace extensions {
38
39namespace {
40
41const char kAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
42const char kPersistentExtensionId[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
43const char kNonPersistentExtensionId[] = "cccccccccccccccccccccccccccccccc";
44
45std::unique_ptr<KeyedService> BuildEventRouter(
46 content::BrowserContext* profile) {
Jinho Bangb5216cec2018-01-17 19:43:1147 return std::make_unique<extensions::EventRouter>(profile, nullptr);
xiyuanf6a4c6a62016-04-19 18:14:5448}
49
Devlin Cronin8e5892f2018-10-04 00:13:4350scoped_refptr<const Extension> CreateApp(const std::string& extension_id,
51 const std::string& version) {
52 scoped_refptr<const Extension> app =
xiyuanf6a4c6a62016-04-19 18:14:5453 ExtensionBuilder()
54 .SetManifest(
55 DictionaryBuilder()
56 .Set("name", "Test app")
57 .Set("version", version)
58 .Set("manifest_version", 2)
59 .Set("app",
60 DictionaryBuilder()
61 .Set("background",
62 DictionaryBuilder()
63 .Set("scripts", ListBuilder()
64 .Append("background.js")
65 .Build())
66 .Build())
67 .Build())
68 .Build())
69 .SetID(extension_id)
70 .Build();
71 return app;
72}
73
Devlin Cronin8e5892f2018-10-04 00:13:4374scoped_refptr<const Extension> CreateExtension(const std::string& extension_id,
75 const std::string& version,
76 bool persistent) {
77 scoped_refptr<const Extension> extension =
xiyuanf6a4c6a62016-04-19 18:14:5478 ExtensionBuilder()
79 .SetManifest(
80 DictionaryBuilder()
81 .Set("name", "Test extension")
82 .Set("version", version)
83 .Set("manifest_version", 2)
84 .Set("background", DictionaryBuilder()
85 .Set("page", "background.html")
Istiaque Ahmed6f874682018-04-13 04:49:4686 .Set("persistent", persistent)
xiyuanf6a4c6a62016-04-19 18:14:5487 .Build())
88 .Build())
89 .SetID(extension_id)
90 .Build();
91 return extension;
92}
93
94ExtensionHost* CreateHost(Profile* profile, const Extension* app) {
95 ProcessManager::Get(profile)->CreateBackgroundHost(
96 app, BackgroundInfo::GetBackgroundURL(app));
97 base::RunLoop().RunUntilIdle();
98
99 return ProcessManager::Get(profile)->GetBackgroundHostForExtension(app->id());
100}
101
102} // namespace
103
104class UpdateInstallGateTest : public testing::Test {
105 public:
106 UpdateInstallGateTest() {
107 profile_manager_.reset(
108 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
109 }
110
111 // testing::Test
112 void SetUp() override {
113 // Must be called from ::testing::Test::SetUp.
114 ASSERT_TRUE(profile_manager_->SetUp());
115
116 const char kUserProfile[] = "[email protected]";
117#if defined(OS_CHROMEOS)
118 const AccountId account_id(AccountId::FromUserEmail(kUserProfile));
119 // Needed to allow ChromeProcessManagerDelegate to allow background pages.
120 fake_user_manager_ = new chromeos::FakeChromeUserManager();
121 // Takes ownership of fake_user_manager_.
Xiyuan Xiadfe3a9f2017-11-13 21:46:26122 scoped_user_manager_enabler_ =
123 std::make_unique<user_manager::ScopedUserManager>(
124 base::WrapUnique(fake_user_manager_));
xiyuanf6a4c6a62016-04-19 18:14:54125 fake_user_manager_->AddUser(account_id);
126 fake_user_manager_->LoginUser(account_id);
127#endif
128 profile_ = profile_manager_->CreateTestingProfile(kUserProfile);
Dominick Ng51154652019-09-25 07:44:20129 base::RunLoop().RunUntilIdle();
xiyuanf6a4c6a62016-04-19 18:14:54130
131 TestExtensionSystem* test_extension_system =
132 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_));
133 service_ = test_extension_system->CreateExtensionService(
134 base::CommandLine::ForCurrentProcess(),
135 base::FilePath() /* install_directory */,
136 false /* autoupdate_enabled */);
137 registry_ = ExtensionRegistry::Get(profile_);
138
139 event_router_ = static_cast<EventRouter*>(
140 EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
Sylvain Defresne711ff6b2018-10-04 12:33:54141 profile_, base::BindRepeating(&BuildEventRouter)));
xiyuanf6a4c6a62016-04-19 18:14:54142
143 delayer_.reset(new UpdateInstallGate(service_));
144
145 new_app_ = CreateApp(kAppId, "2.0");
146 new_persistent_ = CreateExtension(kPersistentExtensionId, "2.0", true);
147 new_none_persistent_ =
148 CreateExtension(kNonPersistentExtensionId, "2.0", false);
149 }
150
151 void TearDown() override { profile_manager_->DeleteAllTestingProfiles(); }
152
153 void AddExistingExtensions() {
Devlin Cronin8e5892f2018-10-04 00:13:43154 scoped_refptr<const Extension> app = CreateApp(kAppId, "1.0");
xiyuanf6a4c6a62016-04-19 18:14:54155 registry_->AddEnabled(app);
156
Devlin Cronin8e5892f2018-10-04 00:13:43157 scoped_refptr<const Extension> persistent =
xiyuanf6a4c6a62016-04-19 18:14:54158 CreateExtension(kPersistentExtensionId, "1.0", true);
159 registry_->AddEnabled(persistent);
160
Devlin Cronin8e5892f2018-10-04 00:13:43161 scoped_refptr<const Extension> none_persistent =
xiyuanf6a4c6a62016-04-19 18:14:54162 CreateExtension(kNonPersistentExtensionId, "1.0", false);
163 registry_->AddEnabled(none_persistent);
164 }
165
166 void MakeExtensionInUse(const std::string& extension_id) {
167 const Extension* const extension =
168 registry_->GetInstalledExtension(extension_id);
169 ASSERT_TRUE(!!extension);
170 ASSERT_TRUE(!!CreateHost(profile_, extension));
171 }
172
173 void MakeExtensionListenForOnUpdateAvailable(
174 const std::string& extension_id) {
175 const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
176 event_router_->AddEventListener(kOnUpdateAvailableEvent, NULL,
177 extension_id);
178 }
179
180 void Check(const Extension* extension,
181 bool is_in_use,
182 bool has_listener,
183 bool install_immediately,
184 InstallGate::Action expected_action) {
185 if (is_in_use)
186 MakeExtensionInUse(extension->id());
187 if (has_listener)
188 MakeExtensionListenForOnUpdateAvailable(extension->id());
189
190 EXPECT_EQ(expected_action,
191 delayer()->ShouldDelay(extension, install_immediately));
192 }
193
194 UpdateInstallGate* delayer() { return delayer_.get(); }
195 ExtensionService* service() { return service_; }
196
197 const Extension* new_app() const { return new_app_.get(); }
198 const Extension* new_persistent() const { return new_persistent_.get(); }
199 const Extension* new_none_persistent() const {
200 return new_none_persistent_.get();
201 }
202
203 private:
204 // Needed by extension system.
Gabriel Charette798fde72019-08-20 22:24:04205 content::BrowserTaskEnvironment task_environment_;
xiyuanf6a4c6a62016-04-19 18:14:54206
207 // Needed to ensure we don't end up creating actual RenderViewHosts
208 // and RenderProcessHosts.
209 content::RenderViewHostTestEnabler render_view_host_test_enabler_;
210
211 TestingProfile* profile_ = nullptr;
212 std::unique_ptr<TestingProfileManager> profile_manager_;
213
214 ExtensionService* service_ = nullptr;
215 ExtensionRegistry* registry_ = nullptr;
216 EventRouter* event_router_ = nullptr;
217
218#if defined(OS_CHROMEOS)
219 // Needed for creating ExtensionService.
220 chromeos::FakeChromeUserManager* fake_user_manager_ = nullptr;
Xiyuan Xiadfe3a9f2017-11-13 21:46:26221 std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_enabler_;
xiyuanf6a4c6a62016-04-19 18:14:54222#endif
223
224 std::unique_ptr<UpdateInstallGate> delayer_;
225
Devlin Cronin8e5892f2018-10-04 00:13:43226 scoped_refptr<const Extension> new_app_;
227 scoped_refptr<const Extension> new_persistent_;
228 scoped_refptr<const Extension> new_none_persistent_;
xiyuanf6a4c6a62016-04-19 18:14:54229
230 DISALLOW_COPY_AND_ASSIGN(UpdateInstallGateTest);
231};
232
233TEST_F(UpdateInstallGateTest, InstallOnServiceNotReady) {
234 ASSERT_FALSE(service()->is_ready());
235 Check(new_app(), false, false, false, InstallGate::INSTALL);
236 Check(new_persistent(), false, false, false, InstallGate::INSTALL);
237 Check(new_none_persistent(), false, false, false, InstallGate::INSTALL);
238}
239
240TEST_F(UpdateInstallGateTest, InstallOnFirstInstall) {
241 service()->Init();
242 Check(new_app(), false, false, false, InstallGate::INSTALL);
243 Check(new_persistent(), false, false, false, InstallGate::INSTALL);
244 Check(new_none_persistent(), false, false, false, InstallGate::INSTALL);
245}
246
247TEST_F(UpdateInstallGateTest, InstallOnInstallImmediately) {
248 service()->Init();
249 AddExistingExtensions();
250
251 const bool kInstallImmediately = true;
252 for (bool in_use : {false, true}) {
253 for (bool has_listener : {false, true}) {
254 Check(new_app(), in_use, has_listener, kInstallImmediately,
255 InstallGate::INSTALL);
256 Check(new_persistent(), in_use, has_listener, kInstallImmediately,
257 InstallGate::INSTALL);
258 Check(new_none_persistent(), in_use, has_listener, kInstallImmediately,
259 InstallGate::INSTALL);
260 }
261 }
262}
263
264TEST_F(UpdateInstallGateTest, DelayInstallWhenInUse) {
265 service()->Init();
266 AddExistingExtensions();
267
268 const bool kInUse = true;
269 const bool kDontInstallImmediately = false;
270 for (bool has_listener : {false, true}) {
271 Check(new_app(), kInUse, has_listener, kDontInstallImmediately,
272 InstallGate::DELAY);
273 Check(new_persistent(), kInUse, has_listener, kDontInstallImmediately,
274 has_listener ? InstallGate::DELAY : InstallGate::INSTALL);
275 Check(new_none_persistent(), kInUse, has_listener, kDontInstallImmediately,
276 InstallGate::DELAY);
277 }
278}
279
280} // namespace extensions