1 // Copyright 2018 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 "extensions/shell/browser/shell_keep_alive_requester.h"
6
7 #include <memory>
8
9 #include "apps/app_lifetime_monitor_factory.h"
10 #include "base/macros.h"
11 #include "components/keep_alive_registry/keep_alive_registry.h"
12 #include "content/public/browser/browser_context.h"
13 #include "extensions/browser/disable_reason.h"
14 #include "extensions/browser/extension_prefs.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/extensions_test.h"
17 #include "extensions/browser/unloaded_extension_reason.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/extension_builder.h"
20 #include "extensions/common/extension_id.h"
21
22 namespace extensions {
23
24 class ShellKeepAliveRequesterTest : public ExtensionsTest {
25 protected:
26 ShellKeepAliveRequesterTest() = default;
27 ~ShellKeepAliveRequesterTest() override = default;
28
SetUp()29 void SetUp() override {
30 // Register factory so it's created with the BrowserContext.
31 apps::AppLifetimeMonitorFactory::GetInstance();
32
33 ExtensionsTest::SetUp();
34
35 keep_alive_requester_ =
36 std::make_unique<ShellKeepAliveRequester>(browser_context());
37 }
38
TearDown()39 void TearDown() override {
40 keep_alive_requester_.reset();
41
42 ExtensionsTest::TearDown();
43 }
44
45 protected:
46 std::unique_ptr<ShellKeepAliveRequester> keep_alive_requester_;
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(ShellKeepAliveRequesterTest);
50 };
51
52 // Tests with an extension.
TEST_F(ShellKeepAliveRequesterTest,Extension)53 TEST_F(ShellKeepAliveRequesterTest, Extension) {
54 scoped_refptr<const Extension> extension =
55 ExtensionBuilder("extension", ExtensionBuilder::Type::EXTENSION).Build();
56
57 // No keep-alive is used for extensions that aren't platform apps.
58 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
59 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
60
61 ExtensionPrefs::Get(browser_context())
62 ->AddDisableReason(extension->id(), disable_reason::DISABLE_RELOAD);
63 keep_alive_requester_->OnExtensionUnloaded(browser_context(), extension.get(),
64 UnloadedExtensionReason::DISABLE);
65 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
66 }
67
68 // Tests with a platform app.
TEST_F(ShellKeepAliveRequesterTest,PlatformApp)69 TEST_F(ShellKeepAliveRequesterTest, PlatformApp) {
70 scoped_refptr<const Extension> extension =
71 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
72 .Build();
73 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
74
75 // Expect a keep-alive while waiting for the app to launch a window.
76 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
77 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
78 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
79
80 // No keep-alives are registered if the extension stops running.
81 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
82 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
83 }
84
85 // Tests with a platform app that doesn't open a window.
TEST_F(ShellKeepAliveRequesterTest,PlatformAppNoWindow)86 TEST_F(ShellKeepAliveRequesterTest, PlatformAppNoWindow) {
87 scoped_refptr<const Extension> extension =
88 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
89 .Build();
90 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
91
92 // Expect a keep-alive while waiting for the app to launch a window.
93 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
94
95 // Eventually, the app's background host is destroyed.
96 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
97 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
98 }
99
100 // Tests with a platform app that is reloaded.
TEST_F(ShellKeepAliveRequesterTest,PlatformAppReload)101 TEST_F(ShellKeepAliveRequesterTest, PlatformAppReload) {
102 scoped_refptr<const Extension> extension =
103 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
104 .Build();
105 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
106
107 // Expect a keep-alive while waiting for the app to launch a window.
108 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
109 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
110 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
111
112 // Disable the app for a reload.
113 keep_alive_requester_->StartTrackingReload(extension.get());
114 ExtensionPrefs::Get(browser_context())
115 ->AddDisableReason(extension->id(), disable_reason::DISABLE_RELOAD);
116 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
117 keep_alive_requester_->OnExtensionUnloaded(browser_context(), extension.get(),
118 UnloadedExtensionReason::DISABLE);
119
120 // Expect a keep-alive while waiting for the app to finish reloading.
121 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
122 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
123 keep_alive_requester_->StopTrackingReload(extension->id());
124
125 // Expect a keep-alive while waiting for the app to launch a window again.
126 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
127 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
128 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
129 }
130
131 // Tests with a platform app that is reloaded, but fails to load.
TEST_F(ShellKeepAliveRequesterTest,PlatformAppReloadFailure)132 TEST_F(ShellKeepAliveRequesterTest, PlatformAppReloadFailure) {
133 scoped_refptr<const Extension> extension =
134 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
135 .Build();
136 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
137
138 // Expect a keep-alive while waiting for the app to launch a window.
139 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
140 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
141 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
142
143 // Disable the app for a reload.
144 keep_alive_requester_->StartTrackingReload(extension.get());
145 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
146 ExtensionPrefs::Get(browser_context())
147 ->AddDisableReason(extension->id(), disable_reason::DISABLE_RELOAD);
148 keep_alive_requester_->OnExtensionUnloaded(browser_context(), extension.get(),
149 UnloadedExtensionReason::DISABLE);
150
151 // Expect a keep-alive while waiting for the app to finish reloading that is
152 // removed when the app fails to load.
153 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
154 keep_alive_requester_->StopTrackingReload(extension->id());
155 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
156 }
157
158 // Tests with a platform app that reloads before opening a window.
TEST_F(ShellKeepAliveRequesterTest,PlatformAppNoWindowReload)159 TEST_F(ShellKeepAliveRequesterTest, PlatformAppNoWindowReload) {
160 scoped_refptr<const Extension> extension =
161 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
162 .Build();
163 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
164
165 // Expect a keep-alive while waiting for the app to launch a window.
166 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
167
168 // Disable the app for a reload.
169 keep_alive_requester_->StartTrackingReload(extension.get());
170 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
171 ExtensionPrefs::Get(browser_context())
172 ->AddDisableReason(extension->id(), disable_reason::DISABLE_RELOAD);
173 keep_alive_requester_->OnExtensionUnloaded(browser_context(), extension.get(),
174 UnloadedExtensionReason::DISABLE);
175
176 // Expect a keep-alive while waiting for the app to finish reloading.
177 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
178 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
179 keep_alive_requester_->StopTrackingReload(extension->id());
180
181 // Expect a keep-alive while waiting for the app to launch a window.
182 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
183 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
184 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
185 }
186
187 // Tests with a platform app that is reloaded, but doesn't open a window again.
TEST_F(ShellKeepAliveRequesterTest,PlatformAppReloadNoWindow)188 TEST_F(ShellKeepAliveRequesterTest, PlatformAppReloadNoWindow) {
189 scoped_refptr<const Extension> extension =
190 ExtensionBuilder("platform_app", ExtensionBuilder::Type::PLATFORM_APP)
191 .Build();
192 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
193
194 // Expect a keep-alive while waiting for the app to launch a window.
195 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
196 keep_alive_requester_->OnAppActivated(browser_context(), extension->id());
197 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
198
199 // Disable the app for a reload.
200 keep_alive_requester_->StartTrackingReload(extension.get());
201 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
202 ExtensionPrefs::Get(browser_context())
203 ->AddDisableReason(extension->id(), disable_reason::DISABLE_RELOAD);
204 keep_alive_requester_->OnExtensionUnloaded(browser_context(), extension.get(),
205 UnloadedExtensionReason::DISABLE);
206
207 // Expect a keep-alive while waiting for the app to finish reloading.
208 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
209 keep_alive_requester_->OnExtensionLoaded(browser_context(), extension.get());
210 keep_alive_requester_->StopTrackingReload(extension->id());
211
212 // Expect a keep-alive while waiting for the app to launch a window again.
213 EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
214
215 // Eventually the app stops.
216 keep_alive_requester_->OnAppStop(browser_context(), extension->id());
217 EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
218 }
219
220 } // namespace extensions
221