blob: 12c2c1bb44a4db02d9f79470b64cc56e8c6bb73a [file] [log] [blame]
[email protected]bcabac762013-05-29 23:33:241// Copyright 2013 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// This file contains tests for extension loading, reloading, and
6// unloading behavior.
7
[email protected]bcabac762013-05-29 23:33:248#include "base/run_loop.h"
[email protected]44580842013-07-09 21:36:539#include "base/strings/stringprintf.h"
[email protected]ca975942014-01-07 12:06:4710#include "base/version.h"
avia2f4804a2015-12-24 23:11:1311#include "build/build_config.h"
rockota34fed222015-09-25 21:56:3112#include "chrome/browser/extensions/devtools_util.h"
[email protected]bcabac762013-05-29 23:33:2413#include "chrome/browser/extensions/extension_browsertest.h"
rockota34fed222015-09-25 21:56:3114#include "chrome/browser/extensions/extension_service.h"
[email protected]44580842013-07-09 21:36:5315#include "chrome/browser/extensions/test_extension_dir.h"
[email protected]ca975942014-01-07 12:06:4716#include "chrome/browser/profiles/profile.h"
[email protected]bcabac762013-05-29 23:33:2417#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/test/base/in_process_browser_test.h"
19#include "chrome/test/base/ui_test_utils.h"
rockota34fed222015-09-25 21:56:3120#include "content/public/browser/devtools_agent_host.h"
rob1166ab32016-02-29 20:26:0221#include "content/public/test/browser_test_utils.h"
[email protected]ca975942014-01-07 12:06:4722#include "extensions/browser/extension_registry.h"
rockota34fed222015-09-25 21:56:3123#include "extensions/browser/process_manager.h"
robertshield9cf42462017-07-19 23:44:0824#include "extensions/common/permissions/permissions_data.h"
rob1166ab32016-02-29 20:26:0225#include "extensions/test/extension_test_message_listener.h"
[email protected]bcabac762013-05-29 23:33:2426#include "net/test/embedded_test_server/embedded_test_server.h"
27#include "testing/gmock/include/gmock/gmock.h"
28
wychen7b07e7b2017-01-10 17:48:2929#if defined(OS_WIN)
30#include "base/win/windows_version.h"
31#endif
32
[email protected]bcabac762013-05-29 23:33:2433namespace extensions {
34namespace {
35
[email protected]bcabac762013-05-29 23:33:2436class ExtensionLoadingTest : public ExtensionBrowserTest {
37};
38
39// Check the fix for http://crbug.com/178542.
40IN_PROC_BROWSER_TEST_F(ExtensionLoadingTest,
41 UpgradeAfterNavigatingFromOverriddenNewTabPage) {
42 embedded_test_server()->ServeFilesFromDirectory(
43 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
svaldeza01f7d92015-11-18 17:47:5644 ASSERT_TRUE(embedded_test_server()->Start());
[email protected]bcabac762013-05-29 23:33:2445
46 TestExtensionDir extension_dir;
robertshield9cf42462017-07-19 23:44:0847 const char kManifestTemplate[] =
[email protected]44580842013-07-09 21:36:5348 "{"
rockota34fed222015-09-25 21:56:3149 " 'name': 'Overrides New Tab',"
50 " 'version': '%d',"
51 " 'description': 'Overrides New Tab',"
52 " 'manifest_version': 2,"
53 " 'background': {"
54 " 'persistent': false,"
55 " 'scripts': ['event.js']"
[email protected]44580842013-07-09 21:36:5356 " },"
rockota34fed222015-09-25 21:56:3157 " 'chrome_url_overrides': {"
58 " 'newtab': 'newtab.html'"
[email protected]44580842013-07-09 21:36:5359 " }"
60 "}";
rockota34fed222015-09-25 21:56:3161 extension_dir.WriteManifestWithSingleQuotes(
robertshield9cf42462017-07-19 23:44:0862 base::StringPrintf(kManifestTemplate, 1));
[email protected]bcabac762013-05-29 23:33:2463 extension_dir.WriteFile(FILE_PATH_LITERAL("event.js"), "");
64 extension_dir.WriteFile(FILE_PATH_LITERAL("newtab.html"),
65 "<h1>Overridden New Tab Page</h1>");
66
67 const Extension* new_tab_extension =
68 InstallExtension(extension_dir.Pack(), 1 /*new install*/);
69 ASSERT_TRUE(new_tab_extension);
70
71 // Visit the New Tab Page to get a renderer using the extension into history.
72 ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab"));
73
74 // Navigate that tab to a non-extension URL to swap out the extension's
75 // renderer.
76 const GURL test_link_from_NTP =
77 embedded_test_server()->GetURL("/README.chromium");
78 EXPECT_THAT(test_link_from_NTP.spec(), testing::EndsWith("/README.chromium"))
79 << "Check that the test server started.";
80 NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
81 test_link_from_NTP);
82
83 // Increase the extension's version.
rockota34fed222015-09-25 21:56:3184 extension_dir.WriteManifestWithSingleQuotes(
robertshield9cf42462017-07-19 23:44:0885 base::StringPrintf(kManifestTemplate, 2));
[email protected]bcabac762013-05-29 23:33:2486
87 // Upgrade the extension.
88 new_tab_extension = UpdateExtension(
89 new_tab_extension->id(), extension_dir.Pack(), 0 /*expected upgrade*/);
90 EXPECT_THAT(new_tab_extension->version()->components(),
91 testing::ElementsAre(2));
92
93 // The extension takes a couple round-trips to the renderer in order
94 // to crash, so open a new tab to wait long enough.
95 AddTabAtIndex(browser()->tab_strip_model()->count(),
96 GURL("http://www.google.com/"),
Sylvain Defresnec6ccc77d2014-09-19 10:19:3597 ui::PAGE_TRANSITION_TYPED);
[email protected]bcabac762013-05-29 23:33:2498
99 // Check that the extension hasn't crashed.
[email protected]ca975942014-01-07 12:06:47100 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
101 EXPECT_EQ(0U, registry->terminated_extensions().size());
102 EXPECT_TRUE(registry->enabled_extensions().Contains(new_tab_extension->id()));
[email protected]bcabac762013-05-29 23:33:24103}
104
robertshield9cf42462017-07-19 23:44:08105IN_PROC_BROWSER_TEST_F(ExtensionLoadingTest,
106 UpgradeAddingNewTabPagePermissionNoPrompt) {
107 embedded_test_server()->ServeFilesFromDirectory(
108 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
109 ASSERT_TRUE(embedded_test_server()->Start());
110
111 TestExtensionDir extension_dir;
112 const char kManifestTemplate[] =
113 "{"
114 " 'name': 'Overrides New Tab',"
115 " 'version': '%d',"
116 " 'description': 'Will override New Tab soon',"
117 " %s" // Placeholder for future NTP url override block.
118 " 'manifest_version': 2"
119 "}";
120 extension_dir.WriteManifestWithSingleQuotes(
121 base::StringPrintf(kManifestTemplate, 1, ""));
122 extension_dir.WriteFile(FILE_PATH_LITERAL("event.js"), "");
123 extension_dir.WriteFile(FILE_PATH_LITERAL("newtab.html"),
124 "<h1>Overridden New Tab Page</h1>");
125
126 const Extension* new_tab_extension =
127 InstallExtension(extension_dir.Pack(), 1 /*new install*/);
128 ASSERT_TRUE(new_tab_extension);
129
130 EXPECT_FALSE(new_tab_extension->permissions_data()->HasAPIPermission(
131 APIPermission::kNewTabPageOverride));
132
133 // Navigate that tab to a non-extension URL to swap out the extension's
134 // renderer.
135 const GURL test_link_from_ntp =
136 embedded_test_server()->GetURL("/README.chromium");
137 EXPECT_THAT(test_link_from_ntp.spec(), testing::EndsWith("/README.chromium"))
138 << "Check that the test server started.";
139 NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
140 test_link_from_ntp);
141
142 // Increase the extension's version and add the NTP url override which will
143 // add the kNewTabPageOverride permission.
144 const char ntp_override_string[] =
145 " 'chrome_url_overrides': {"
146 " 'newtab': 'newtab.html'"
147 " },";
148 extension_dir.WriteManifestWithSingleQuotes(
149 base::StringPrintf(kManifestTemplate, 2, ntp_override_string));
150
151 // Upgrade the extension, ensure that the upgrade 'worked' in the sense that
152 // the extension is still present and not disabled and that it now has the
153 // new API permission.
154 // TODO(robertshield): Update this once most of the population is on M62+
155 // and adding NTP permissions implies a permission upgrade.
156 new_tab_extension = UpdateExtension(
157 new_tab_extension->id(), extension_dir.Pack(), 0 /*expected upgrade*/);
158 ASSERT_NE(nullptr, new_tab_extension);
159
160 EXPECT_TRUE(new_tab_extension->permissions_data()->HasAPIPermission(
161 APIPermission::kNewTabPageOverride));
162 EXPECT_THAT(new_tab_extension->version()->components(),
163 testing::ElementsAre(2));
164}
165
rockota34fed222015-09-25 21:56:31166// Tests the behavior described in http://crbug.com/532088.
167IN_PROC_BROWSER_TEST_F(ExtensionLoadingTest,
168 KeepAliveWithDevToolsOpenOnReload) {
169 embedded_test_server()->ServeFilesFromDirectory(
170 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
svaldeza01f7d92015-11-18 17:47:56171 ASSERT_TRUE(embedded_test_server()->Start());
rockota34fed222015-09-25 21:56:31172
173 TestExtensionDir extension_dir;
174 const char manifest_contents[] =
175 "{"
176 " 'name': 'Test With Lazy Background Page',"
177 " 'version': '0',"
178 " 'manifest_version': 2,"
179 " 'app': {"
180 " 'background': {"
181 " 'scripts': ['event.js']"
182 " }"
183 " }"
184 "}";
185 extension_dir.WriteManifestWithSingleQuotes(manifest_contents);
186 extension_dir.WriteFile(FILE_PATH_LITERAL("event.js"), "");
187
188 const Extension* extension =
189 InstallExtension(extension_dir.Pack(), 1 /*new install*/);
190 ASSERT_TRUE(extension);
191 std::string extension_id = extension->id();
192
193 ProcessManager* process_manager = ProcessManager::Get(profile());
194 EXPECT_EQ(0, process_manager->GetLazyKeepaliveCount(extension));
195
196 devtools_util::InspectBackgroundPage(extension, profile());
197 EXPECT_EQ(1, process_manager->GetLazyKeepaliveCount(extension));
198
199 // Opening DevTools will cause the background page to load. Wait for it.
200 WaitForExtensionViewsToLoad();
201
202 ReloadExtension(extension_id);
203
204 // Flush the MessageLoop to ensure that DevTools has a chance to be reattached
205 // and the background page has a chance to begin reloading.
206 base::RunLoop().RunUntilIdle();
207
208 // And wait for the background page to finish loading again.
209 WaitForExtensionViewsToLoad();
210
211 // Ensure that our DevtoolsAgentHost is actually connected to the new
212 // background WebContents.
213 content::WebContents* background_contents =
214 process_manager->GetBackgroundHostForExtension(extension_id)
215 ->host_contents();
216 EXPECT_TRUE(content::DevToolsAgentHost::HasFor(background_contents));
217
218 // The old Extension object is no longer valid.
219 extension = ExtensionRegistry::Get(profile())
220 ->enabled_extensions().GetByID(extension_id);
221
222 // Keepalive count should stabilize back to 1, because DevTools is still open.
223 EXPECT_EQ(1, process_manager->GetLazyKeepaliveCount(extension));
224}
225
rob1166ab32016-02-29 20:26:02226// Tests whether the extension runtime stays valid when an extension reloads
227// while a devtools extension is hammering the frame with eval requests.
228// Regression test for https://crbug.com/544182
229IN_PROC_BROWSER_TEST_F(ExtensionLoadingTest, RuntimeValidWhileDevToolsOpen) {
230 TestExtensionDir devtools_dir;
231 TestExtensionDir inspect_dir;
232
233 const char kDevtoolsManifest[] =
234 "{"
235 " 'name': 'Devtools',"
236 " 'version': '1',"
237 " 'manifest_version': 2,"
238 " 'devtools_page': 'devtools.html'"
239 "}";
240
241 const char kDevtoolsJs[] =
242 "setInterval(function() {"
243 " chrome.devtools.inspectedWindow.eval('1', function() {"
244 " });"
245 "}, 4);"
246 "chrome.test.sendMessage('devtools_page_ready');";
247
248 const char kTargetManifest[] =
249 "{"
250 " 'name': 'Inspect target',"
251 " 'version': '1',"
252 " 'manifest_version': 2,"
253 " 'background': {"
254 " 'scripts': ['background.js']"
255 " }"
256 "}";
257
258 // A script to duck-type whether it runs in a background page.
259 const char kTargetJs[] =
260 "var is_valid = !!(chrome.tabs && chrome.tabs.create);";
261
262 devtools_dir.WriteManifestWithSingleQuotes(kDevtoolsManifest);
263 devtools_dir.WriteFile(FILE_PATH_LITERAL("devtools.js"), kDevtoolsJs);
264 devtools_dir.WriteFile(FILE_PATH_LITERAL("devtools.html"),
265 "<script src='devtools.js'></script>");
266
267 inspect_dir.WriteManifestWithSingleQuotes(kTargetManifest);
268 inspect_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kTargetJs);
vabr9142fe22016-09-08 13:19:22269 const Extension* devtools_ext = LoadExtension(devtools_dir.UnpackedPath());
rob1166ab32016-02-29 20:26:02270 ASSERT_TRUE(devtools_ext);
271
vabr9142fe22016-09-08 13:19:22272 const Extension* inspect_ext = LoadExtension(inspect_dir.UnpackedPath());
rob1166ab32016-02-29 20:26:02273 ASSERT_TRUE(inspect_ext);
274 const std::string inspect_ext_id = inspect_ext->id();
275
276 // Open the devtools and wait until the devtools_page is ready.
277 ExtensionTestMessageListener devtools_ready("devtools_page_ready", false);
278 devtools_util::InspectBackgroundPage(inspect_ext, profile());
279 ASSERT_TRUE(devtools_ready.WaitUntilSatisfied());
280
281 // Reload the extension. The devtools window will stay open, but temporarily
282 // be detached. As soon as the background is attached again, the devtools
283 // continues with spamming eval requests.
284 ReloadExtension(inspect_ext_id);
285 WaitForExtensionViewsToLoad();
286
287 content::WebContents* bg_contents =
288 ProcessManager::Get(profile())
289 ->GetBackgroundHostForExtension(inspect_ext_id)
290 ->host_contents();
291 ASSERT_TRUE(bg_contents);
292
293 // Now check whether the extension runtime is valid (see kTargetJs).
294 bool is_valid = false;
295 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
296 bg_contents, "domAutomationController.send(is_valid);", &is_valid));
297 EXPECT_TRUE(is_valid);
298}
299
[email protected]bcabac762013-05-29 23:33:24300} // namespace
301} // namespace extensions