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