blob: 00c7866d47daf110b4e3de19f38db914470c3a4a [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"
Yuta Hijikata1290fee22020-11-25 09:46:2813#include "build/chromeos_buildflags.h"
xiyuanf6a4c6a62016-04-19 18:14:5414#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/extensions/test_extension_system.h"
16#include "chrome/test/base/testing_browser_process.h"
17#include "chrome/test/base/testing_profile.h"
18#include "chrome/test/base/testing_profile_manager.h"
Gabriel Charettec7108742019-08-23 03:31:4019#include "content/public/test/browser_task_environment.h"
xiyuanf6a4c6a62016-04-19 18:14:5420#include "content/public/test/test_renderer_host.h"
21#include "extensions/browser/event_router.h"
22#include "extensions/browser/event_router_factory.h"
23#include "extensions/browser/extension_host.h"
24#include "extensions/browser/extension_prefs.h"
25#include "extensions/browser/extension_registry.h"
26#include "extensions/common/extension_builder.h"
27#include "extensions/common/manifest_handlers/background_info.h"
28#include "extensions/common/value_builder.h"
29#include "testing/gtest/include/gtest/gtest.h"
30
Yuta Hijikata1290fee22020-11-25 09:46:2831#if BUILDFLAG(IS_CHROMEOS_ASH)
Henrique Ferreiro1ab7f12f2021-03-04 19:54:4032#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2633#include "components/user_manager/scoped_user_manager.h"
xiyuanf6a4c6a62016-04-19 18:14:5434#endif
35
36namespace extensions {
37
38namespace {
39
40const char kAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
41const char kPersistentExtensionId[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
42const char kNonPersistentExtensionId[] = "cccccccccccccccccccccccccccccccc";
43
44std::unique_ptr<KeyedService> BuildEventRouter(
45 content::BrowserContext* profile) {
Jinho Bangb5216cec2018-01-17 19:43:1146 return std::make_unique<extensions::EventRouter>(profile, nullptr);
xiyuanf6a4c6a62016-04-19 18:14:5447}
48
Devlin Cronin8e5892f2018-10-04 00:13:4349scoped_refptr<const Extension> CreateApp(const std::string& extension_id,
50 const std::string& version) {
51 scoped_refptr<const Extension> app =
xiyuanf6a4c6a62016-04-19 18:14:5452 ExtensionBuilder()
53 .SetManifest(
54 DictionaryBuilder()
55 .Set("name", "Test app")
56 .Set("version", version)
57 .Set("manifest_version", 2)
58 .Set("app",
59 DictionaryBuilder()
60 .Set("background",
61 DictionaryBuilder()
62 .Set("scripts", ListBuilder()
63 .Append("background.js")
64 .Build())
65 .Build())
66 .Build())
67 .Build())
68 .SetID(extension_id)
69 .Build();
70 return app;
71}
72
Devlin Cronin8e5892f2018-10-04 00:13:4373scoped_refptr<const Extension> CreateExtension(const std::string& extension_id,
74 const std::string& version,
75 bool persistent) {
76 scoped_refptr<const Extension> extension =
xiyuanf6a4c6a62016-04-19 18:14:5477 ExtensionBuilder()
78 .SetManifest(
79 DictionaryBuilder()
80 .Set("name", "Test extension")
81 .Set("version", version)
82 .Set("manifest_version", 2)
83 .Set("background", DictionaryBuilder()
84 .Set("page", "background.html")
Istiaque Ahmed6f874682018-04-13 04:49:4685 .Set("persistent", persistent)
xiyuanf6a4c6a62016-04-19 18:14:5486 .Build())
87 .Build())
88 .SetID(extension_id)
89 .Build();
90 return extension;
91}
92
93ExtensionHost* CreateHost(Profile* profile, const Extension* app) {
94 ProcessManager::Get(profile)->CreateBackgroundHost(
95 app, BackgroundInfo::GetBackgroundURL(app));
96 base::RunLoop().RunUntilIdle();
97
98 return ProcessManager::Get(profile)->GetBackgroundHostForExtension(app->id());
99}
100
101} // namespace
102
103class UpdateInstallGateTest : public testing::Test {
104 public:
105 UpdateInstallGateTest() {
Peter Boström924f8032021-04-02 20:36:02106 profile_manager_ = std::make_unique<TestingProfileManager>(
107 TestingBrowserProcess::GetGlobal());
xiyuanf6a4c6a62016-04-19 18:14:54108 }
109
Peter Boström6316db82021-09-24 16:15:11110 UpdateInstallGateTest(const UpdateInstallGateTest&) = delete;
111 UpdateInstallGateTest& operator=(const UpdateInstallGateTest&) = delete;
112
xiyuanf6a4c6a62016-04-19 18:14:54113 // testing::Test
114 void SetUp() override {
115 // Must be called from ::testing::Test::SetUp.
116 ASSERT_TRUE(profile_manager_->SetUp());
117
118 const char kUserProfile[] = "[email protected]";
Yuta Hijikata1290fee22020-11-25 09:46:28119#if BUILDFLAG(IS_CHROMEOS_ASH)
xiyuanf6a4c6a62016-04-19 18:14:54120 const AccountId account_id(AccountId::FromUserEmail(kUserProfile));
121 // Needed to allow ChromeProcessManagerDelegate to allow background pages.
Henrique Ferreiro4c2fc0a2021-03-26 10:42:47122 fake_user_manager_ = new ash::FakeChromeUserManager();
xiyuanf6a4c6a62016-04-19 18:14:54123 // Takes ownership of fake_user_manager_.
Xiyuan Xiadfe3a9f2017-11-13 21:46:26124 scoped_user_manager_enabler_ =
125 std::make_unique<user_manager::ScopedUserManager>(
126 base::WrapUnique(fake_user_manager_));
xiyuanf6a4c6a62016-04-19 18:14:54127 fake_user_manager_->AddUser(account_id);
128 fake_user_manager_->LoginUser(account_id);
129#endif
130 profile_ = profile_manager_->CreateTestingProfile(kUserProfile);
Dominick Ng51154652019-09-25 07:44:20131 base::RunLoop().RunUntilIdle();
xiyuanf6a4c6a62016-04-19 18:14:54132
Ghazale Hosseinabadi1d810e92020-06-01 20:43:02133 system_ = static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_));
134 service_ = system_->CreateExtensionService(
xiyuanf6a4c6a62016-04-19 18:14:54135 base::CommandLine::ForCurrentProcess(),
136 base::FilePath() /* install_directory */,
137 false /* autoupdate_enabled */);
138 registry_ = ExtensionRegistry::Get(profile_);
139
140 event_router_ = static_cast<EventRouter*>(
141 EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
Sylvain Defresne711ff6b2018-10-04 12:33:54142 profile_, base::BindRepeating(&BuildEventRouter)));
xiyuanf6a4c6a62016-04-19 18:14:54143
Peter Boström924f8032021-04-02 20:36:02144 delayer_ = std::make_unique<UpdateInstallGate>(profile_);
xiyuanf6a4c6a62016-04-19 18:14:54145
146 new_app_ = CreateApp(kAppId, "2.0");
147 new_persistent_ = CreateExtension(kPersistentExtensionId, "2.0", true);
148 new_none_persistent_ =
149 CreateExtension(kNonPersistentExtensionId, "2.0", false);
150 }
151
152 void TearDown() override { profile_manager_->DeleteAllTestingProfiles(); }
153
154 void AddExistingExtensions() {
Devlin Cronin8e5892f2018-10-04 00:13:43155 scoped_refptr<const Extension> app = CreateApp(kAppId, "1.0");
xiyuanf6a4c6a62016-04-19 18:14:54156 registry_->AddEnabled(app);
157
Devlin Cronin8e5892f2018-10-04 00:13:43158 scoped_refptr<const Extension> persistent =
xiyuanf6a4c6a62016-04-19 18:14:54159 CreateExtension(kPersistentExtensionId, "1.0", true);
160 registry_->AddEnabled(persistent);
161
Devlin Cronin8e5892f2018-10-04 00:13:43162 scoped_refptr<const Extension> none_persistent =
xiyuanf6a4c6a62016-04-19 18:14:54163 CreateExtension(kNonPersistentExtensionId, "1.0", false);
164 registry_->AddEnabled(none_persistent);
165 }
166
167 void MakeExtensionInUse(const std::string& extension_id) {
168 const Extension* const extension =
169 registry_->GetInstalledExtension(extension_id);
Lei Zhang90c474642020-06-12 01:26:22170 ASSERT_TRUE(extension);
171 ASSERT_TRUE(CreateHost(profile_, extension));
xiyuanf6a4c6a62016-04-19 18:14:54172 }
173
174 void MakeExtensionListenForOnUpdateAvailable(
175 const std::string& extension_id) {
176 const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
177 event_router_->AddEventListener(kOnUpdateAvailableEvent, NULL,
178 extension_id);
179 }
180
181 void Check(const Extension* extension,
182 bool is_in_use,
183 bool has_listener,
184 bool install_immediately,
185 InstallGate::Action expected_action) {
186 if (is_in_use)
187 MakeExtensionInUse(extension->id());
188 if (has_listener)
189 MakeExtensionListenForOnUpdateAvailable(extension->id());
190
191 EXPECT_EQ(expected_action,
192 delayer()->ShouldDelay(extension, install_immediately));
193 }
194
195 UpdateInstallGate* delayer() { return delayer_.get(); }
Ghazale Hosseinabadi1d810e92020-06-01 20:43:02196 ExtensionSystem* system() { return system_; }
xiyuanf6a4c6a62016-04-19 18:14:54197 ExtensionService* service() { return service_; }
198
199 const Extension* new_app() const { return new_app_.get(); }
200 const Extension* new_persistent() const { return new_persistent_.get(); }
201 const Extension* new_none_persistent() const {
202 return new_none_persistent_.get();
203 }
204
205 private:
206 // Needed by extension system.
Gabriel Charette798fde72019-08-20 22:24:04207 content::BrowserTaskEnvironment task_environment_;
xiyuanf6a4c6a62016-04-19 18:14:54208
209 // Needed to ensure we don't end up creating actual RenderViewHosts
210 // and RenderProcessHosts.
211 content::RenderViewHostTestEnabler render_view_host_test_enabler_;
212
213 TestingProfile* profile_ = nullptr;
214 std::unique_ptr<TestingProfileManager> profile_manager_;
215
Ghazale Hosseinabadi1d810e92020-06-01 20:43:02216 TestExtensionSystem* system_ = nullptr;
xiyuanf6a4c6a62016-04-19 18:14:54217 ExtensionService* service_ = nullptr;
218 ExtensionRegistry* registry_ = nullptr;
219 EventRouter* event_router_ = nullptr;
220
Yuta Hijikata1290fee22020-11-25 09:46:28221#if BUILDFLAG(IS_CHROMEOS_ASH)
xiyuanf6a4c6a62016-04-19 18:14:54222 // Needed for creating ExtensionService.
Henrique Ferreiro4c2fc0a2021-03-26 10:42:47223 ash::FakeChromeUserManager* fake_user_manager_ = nullptr;
Xiyuan Xiadfe3a9f2017-11-13 21:46:26224 std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_enabler_;
xiyuanf6a4c6a62016-04-19 18:14:54225#endif
226
227 std::unique_ptr<UpdateInstallGate> delayer_;
228
Devlin Cronin8e5892f2018-10-04 00:13:43229 scoped_refptr<const Extension> new_app_;
230 scoped_refptr<const Extension> new_persistent_;
231 scoped_refptr<const Extension> new_none_persistent_;
xiyuanf6a4c6a62016-04-19 18:14:54232};
233
234TEST_F(UpdateInstallGateTest, InstallOnServiceNotReady) {
Ghazale Hosseinabadi1d810e92020-06-01 20:43:02235 ASSERT_FALSE(system()->is_ready());
xiyuanf6a4c6a62016-04-19 18:14:54236 Check(new_app(), false, false, false, InstallGate::INSTALL);
237 Check(new_persistent(), false, false, false, InstallGate::INSTALL);
238 Check(new_none_persistent(), false, false, false, InstallGate::INSTALL);
239}
240
241TEST_F(UpdateInstallGateTest, InstallOnFirstInstall) {
242 service()->Init();
243 Check(new_app(), false, false, false, InstallGate::INSTALL);
244 Check(new_persistent(), false, false, false, InstallGate::INSTALL);
245 Check(new_none_persistent(), false, false, false, InstallGate::INSTALL);
246}
247
248TEST_F(UpdateInstallGateTest, InstallOnInstallImmediately) {
249 service()->Init();
250 AddExistingExtensions();
251
252 const bool kInstallImmediately = true;
253 for (bool in_use : {false, true}) {
254 for (bool has_listener : {false, true}) {
255 Check(new_app(), in_use, has_listener, kInstallImmediately,
256 InstallGate::INSTALL);
257 Check(new_persistent(), in_use, has_listener, kInstallImmediately,
258 InstallGate::INSTALL);
259 Check(new_none_persistent(), in_use, has_listener, kInstallImmediately,
260 InstallGate::INSTALL);
261 }
262 }
263}
264
265TEST_F(UpdateInstallGateTest, DelayInstallWhenInUse) {
266 service()->Init();
267 AddExistingExtensions();
268
269 const bool kInUse = true;
270 const bool kDontInstallImmediately = false;
271 for (bool has_listener : {false, true}) {
272 Check(new_app(), kInUse, has_listener, kDontInstallImmediately,
273 InstallGate::DELAY);
274 Check(new_persistent(), kInUse, has_listener, kDontInstallImmediately,
275 has_listener ? InstallGate::DELAY : InstallGate::INSTALL);
276 Check(new_none_persistent(), kInUse, has_listener, kDontInstallImmediately,
277 InstallGate::DELAY);
278 }
279}
280
281} // namespace extensions