OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/process_manager.h" | 5 #include "extensions/browser/process_manager.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | |
7 #include "chrome/browser/extensions/browser_action_test_util.h" | 8 #include "chrome/browser/extensions/browser_action_test_util.h" |
8 #include "chrome/browser/extensions/extension_browsertest.h" | 9 #include "chrome/browser/extensions/extension_browsertest.h" |
9 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
11 #include "chrome/browser/extensions/test_extension_dir.h" | |
10 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 12 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
13 #include "chrome/common/extensions/extension_process_policy.h" | |
11 #include "chrome/test/base/in_process_browser_test.h" | 14 #include "chrome/test/base/in_process_browser_test.h" |
12 #include "chrome/test/base/ui_test_utils.h" | 15 #include "chrome/test/base/ui_test_utils.h" |
13 #include "content/public/browser/notification_service.h" | 16 #include "content/public/browser/notification_service.h" |
17 #include "content/public/browser/render_frame_host.h" | |
14 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" |
19 #include "content/public/test/browser_test_utils.h" | |
15 #include "content/public/test/test_utils.h" | 20 #include "content/public/test/test_utils.h" |
21 #include "extensions/common/value_builder.h" | |
22 #include "extensions/test/background_page_watcher.h" | |
23 #include "extensions/test/extension_test_message_listener.h" | |
16 #include "net/dns/mock_host_resolver.h" | 24 #include "net/dns/mock_host_resolver.h" |
17 #include "net/test/embedded_test_server/embedded_test_server.h" | 25 #include "net/test/embedded_test_server/embedded_test_server.h" |
18 | 26 |
19 namespace extensions { | 27 namespace extensions { |
20 | 28 |
21 // Exists as a browser test because ExtensionHosts are hard to create without | 29 // Exists as a browser test because ExtensionHosts are hard to create without |
22 // a real browser. | 30 // a real browser. |
23 typedef ExtensionBrowserTest ProcessManagerBrowserTest; | 31 class ProcessManagerBrowserTest : public ExtensionBrowserTest { |
32 public: | |
33 // Create an extension with web-accessible frames and an optional background | |
34 // page. | |
35 const Extension* CreateExtension(const std::string& name, | |
36 bool has_background_process) { | |
37 scoped_ptr<TestExtensionDir> dir(new TestExtensionDir); | |
38 | |
39 DictionaryBuilder manifest; | |
40 manifest.Set("name", name) | |
41 .Set("version", "1") | |
42 .Set("manifest_version", 2) | |
43 // To allow ExecuteScript* to work. | |
44 .Set("content_security_policy", | |
45 "script-src 'self' 'unsafe-eval'; object-src 'self'") | |
46 .Set("web_accessible_resources", ListBuilder().Append("*")); | |
47 | |
48 if (has_background_process) { | |
49 manifest.Set("background", DictionaryBuilder().Set("page", "bg.html")); | |
50 dir->WriteFile(FILE_PATH_LITERAL("bg.html"), | |
51 "<iframe id=bgframe src=empty.html></iframe>"); | |
52 } | |
53 | |
54 dir->WriteFile(FILE_PATH_LITERAL("blank_iframe.html"), | |
55 "<iframe id=frame0 src='about:blank'></iframe>"); | |
56 | |
57 dir->WriteFile(FILE_PATH_LITERAL("srcdoc_iframe.html"), | |
58 "<iframe id=frame0 srcdoc='Hello world'></iframe>"); | |
59 | |
60 dir->WriteFile(FILE_PATH_LITERAL("two_iframes.html"), | |
61 "<iframe id=frame1 src=empty.html></iframe>" | |
62 "<iframe id=frame2 src=empty.html></iframe>"); | |
63 | |
64 dir->WriteFile(FILE_PATH_LITERAL("empty.html"), ""); | |
65 | |
66 dir->WriteManifest(manifest.ToJSON()); | |
67 | |
68 const Extension* extension = LoadExtension(dir->unpacked_path()); | |
69 EXPECT_TRUE(extension); | |
70 temp_dirs_.push_back(dir.release()); | |
71 return extension; | |
72 } | |
73 | |
74 void NavigateIframeToURLAndWait(content::WebContents* web_contents, | |
75 const std::string iframe_id, | |
76 const GURL& url) { | |
77 // This is an improved version of content::NavigateIframeToURL. Unlike the | |
78 // other method, this does actually wait until the load of all child frames | |
79 // completes. | |
80 std::string script = base::StringPrintf( | |
81 "var frame = document.getElementById('%s');" | |
82 "frame.onload = frame.onerror = function(event) {" | |
83 " frame.onload = frame.onerror = null;" | |
84 " domAutomationController.send(event.type === 'load');" | |
85 "};" | |
86 "frame.src = '%s';", | |
87 iframe_id.c_str(), url.spec().c_str()); | |
88 bool is_loaded = false; | |
89 EXPECT_TRUE(ExecuteScriptAndExtractBool(web_contents, script, &is_loaded)); | |
90 EXPECT_TRUE(is_loaded); | |
ncarter (slow)
2015/11/24 05:22:13
I had a chat with creis, and we'd probably be fine
robwu
2015/11/25 00:44:16
I'll do that in a separate CL to make sure that bi
| |
91 } | |
92 | |
93 size_t IfExtensionsIsolated(size_t if_enabled, size_t if_disabled) { | |
94 return content::AreAllSitesIsolatedForTesting() || | |
95 IsIsolateExtensionsEnabled() ? if_enabled : if_disabled; | |
96 } | |
97 | |
98 private: | |
99 ScopedVector<TestExtensionDir> temp_dirs_; | |
ncarter (slow)
2015/11/24 05:22:13
std::vector<scoped_ptr<TestExtensionDir>>
Since w
robwu
2015/11/25 00:44:17
Done.
| |
100 | |
ncarter (slow)
2015/11/24 05:22:13
nit: no blank line
robwu
2015/11/25 00:44:16
Done.
| |
101 }; | |
24 | 102 |
25 // Test that basic extension loading creates the appropriate ExtensionHosts | 103 // Test that basic extension loading creates the appropriate ExtensionHosts |
26 // and background pages. | 104 // and background pages. |
27 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, | 105 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, |
28 ExtensionHostCreation) { | 106 ExtensionHostCreation) { |
29 ProcessManager* pm = ProcessManager::Get(profile()); | 107 ProcessManager* pm = ProcessManager::Get(profile()); |
30 | 108 |
31 // We start with no background hosts. | 109 // We start with no background hosts. |
32 ASSERT_EQ(0u, pm->background_hosts().size()); | 110 ASSERT_EQ(0u, pm->background_hosts().size()); |
33 ASSERT_EQ(0u, pm->GetAllFrames().size()); | 111 ASSERT_EQ(0u, pm->GetAllFrames().size()); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 content::WebContents* extension_web_contents = | 228 content::WebContents* extension_web_contents = |
151 content::WebContents::FromRenderFrameHost( | 229 content::WebContents::FromRenderFrameHost( |
152 *pm->GetRenderFrameHostsForExtension(extension->id()).begin()); | 230 *pm->GetRenderFrameHostsForExtension(extension->id()).begin()); |
153 EXPECT_TRUE(extension_web_contents->GetSiteInstance() != | 231 EXPECT_TRUE(extension_web_contents->GetSiteInstance() != |
154 tab_web_contents->GetSiteInstance()); | 232 tab_web_contents->GetSiteInstance()); |
155 EXPECT_TRUE(pm->GetSiteInstanceForURL(extension->url()) != | 233 EXPECT_TRUE(pm->GetSiteInstanceForURL(extension->url()) != |
156 tab_web_contents->GetSiteInstance()); | 234 tab_web_contents->GetSiteInstance()); |
157 EXPECT_TRUE(pm->GetBackgroundHostForExtension(extension->id())); | 235 EXPECT_TRUE(pm->GetBackgroundHostForExtension(extension->id())); |
158 } | 236 } |
159 | 237 |
238 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, NoBackgroundPage) { | |
239 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | |
240 | |
241 ProcessManager* pm = ProcessManager::Get(profile()); | |
242 const Extension* extension = | |
243 LoadExtension(test_data_dir_.AppendASCII("api_test") | |
244 .AppendASCII("messaging") | |
245 .AppendASCII("connect_nobackground")); | |
246 ASSERT_TRUE(extension); | |
247 | |
248 // The extension has no background page. | |
249 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
250 | |
251 // Start in a non-extension process, then navigate to an extension process. | |
252 ui_test_utils::NavigateToURL(browser(), | |
253 embedded_test_server()->GetURL("/empty.html")); | |
254 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
255 | |
256 const GURL extension_url = extension->url().Resolve("manifest.json"); | |
257 ui_test_utils::NavigateToURL(browser(), extension_url); | |
258 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
259 | |
260 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); | |
261 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
262 | |
263 ui_test_utils::NavigateToURLWithDisposition( | |
264 browser(), extension_url, NEW_FOREGROUND_TAB, | |
265 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); | |
266 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
267 } | |
268 | |
269 // Tests whether frames are correctly classified. Non-extension frames should | |
270 // never appear in the list. Top-level extension frames should always appear. | |
271 // Child extension frames should only appear if it is hosted in an extension | |
272 // process (i.e. if the top-level frame is an extension page, or if OOP frames | |
273 // are enabled for extensions). | |
274 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, FrameClassification) { | |
275 const Extension* extension1 = CreateExtension("Extension 1", false); | |
276 const Extension* extension2 = CreateExtension("Extension 2", true); | |
277 embedded_test_server()->ServeFilesFromDirectory(extension1->path()); | |
278 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | |
279 | |
280 const GURL ext1_parent_url(extension1->url().Resolve("two_iframes.html")); | |
281 const GURL ext1_empty_url(extension1->url().Resolve("empty.html")); | |
282 const GURL ext2_parent_url(extension2->url().Resolve("two_iframes.html")); | |
283 const GURL ext2_empty_url(extension2->url().Resolve("empty.html")); | |
284 | |
285 ProcessManager* pm = ProcessManager::Get(profile()); | |
286 BackgroundPageWatcher(pm, extension2).WaitForOpen(); | |
287 | |
288 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
289 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
290 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
291 | |
292 ExecuteScriptInBackgroundPageNoWait(extension2->id(), | |
293 "setTimeout(window.close, 0)"); | |
294 BackgroundPageWatcher(pm, extension2).WaitForClose(); | |
295 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
296 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
297 | |
298 ui_test_utils::NavigateToURL( | |
299 browser(), embedded_test_server()->GetURL("/two_iframes.html")); | |
300 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
301 | |
302 content::WebContents* tab = | |
303 browser()->tab_strip_model()->GetActiveWebContents(); | |
304 | |
305 // Tests extension frames in non-extension page. | |
306 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
307 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
308 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
309 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); | |
310 | |
311 NavigateIframeToURLAndWait(tab, "frame2", ext2_empty_url); | |
312 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
313 pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
314 EXPECT_EQ(IfExtensionsIsolated(2, 0), pm->GetAllFrames().size()); | |
315 | |
316 // Tests non-extension page in extension frame | |
317 ui_test_utils::NavigateToURL(browser(), ext1_parent_url); | |
318 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
319 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
320 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
321 | |
322 NavigateIframeToURLAndWait(tab, "frame1", | |
323 embedded_test_server()->GetURL("/empty.html")); | |
324 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
325 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
326 | |
327 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
328 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
329 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
330 | |
331 // Load a frame from another extension. | |
332 NavigateIframeToURLAndWait(tab, "frame1", ext2_empty_url); | |
333 EXPECT_EQ(IfExtensionsIsolated(3, 2), pm->GetAllFrames().size()); | |
334 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
335 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
336 pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
337 | |
338 // Destroy all existing frames by navigating to another extension. | |
339 ui_test_utils::NavigateToURL(browser(), | |
340 extension2->url().Resolve("empty.html")); | |
341 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
342 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
343 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
344 | |
345 // Test about:blank and about:srcdoc child frames. | |
346 ui_test_utils::NavigateToURL(browser(), | |
347 extension2->url().Resolve("srcdoc_iframe.html")); | |
348 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
349 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
350 | |
351 ui_test_utils::NavigateToURL(browser(), | |
352 extension2->url().Resolve("blank_iframe.html")); | |
353 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
354 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
355 | |
356 // Test nested frames (same extension). | |
357 ui_test_utils::NavigateToURL(browser(), ext2_parent_url); | |
358 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
359 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
360 | |
361 NavigateIframeToURLAndWait(tab, "frame1", ext2_parent_url); | |
362 EXPECT_EQ(5u, pm->GetAllFrames().size()); | |
363 EXPECT_EQ(5u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
364 | |
365 // The extension frame from the other extension should not be classified as an | |
366 // extension (unless out-of-process frames are enabled). | |
367 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
368 EXPECT_EQ(IfExtensionsIsolated(3, 2), pm->GetAllFrames().size()); | |
369 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
370 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
371 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
372 | |
373 NavigateIframeToURLAndWait(tab, "frame2", ext1_parent_url); | |
374 EXPECT_EQ(IfExtensionsIsolated(5, 1), pm->GetAllFrames().size()); | |
375 EXPECT_EQ(IfExtensionsIsolated(4, 0), | |
376 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
377 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
378 | |
379 // Crash tab where the top-level frame is an extension frame. | |
380 content::CrashTab(tab); | |
381 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
382 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
383 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
384 | |
385 // Now load an extension page and a non-extension page... | |
386 ui_test_utils::NavigateToURLWithDisposition( | |
387 browser(), ext1_empty_url, NEW_BACKGROUND_TAB, | |
388 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); | |
389 ui_test_utils::NavigateToURL( | |
390 browser(), embedded_test_server()->GetURL("/two_iframes.html")); | |
391 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
392 | |
393 // ... load an extension frame in the non-extension process | |
394 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
395 EXPECT_EQ(IfExtensionsIsolated(2, 1), | |
396 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
397 | |
398 // ... and take down the tab. The extension process is not part of the tab, | |
399 // so it should be kept alive (minus the frames that died). | |
400 content::CrashTab(tab); | |
401 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
402 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
ncarter (slow)
2015/11/24 05:22:13
This test is awesome.
robwu
2015/11/25 00:44:16
Thanks. It was flaky, and I locally ran the test f
ncarter (slow)
2015/11/30 22:56:45
Good find; I like how you handled it. This makes m
| |
403 } | |
404 | |
160 // Verify correct keepalive count behavior on network request events. | 405 // Verify correct keepalive count behavior on network request events. |
161 // Regression test for http://crbug.com/535716. | 406 // Regression test for http://crbug.com/535716. |
162 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, KeepaliveOnNetworkRequest) { | 407 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, KeepaliveOnNetworkRequest) { |
163 // Load an extension with a lazy background page. | 408 // Load an extension with a lazy background page. |
164 scoped_refptr<const Extension> extension = | 409 scoped_refptr<const Extension> extension = |
165 LoadExtension(test_data_dir_.AppendASCII("api_test") | 410 LoadExtension(test_data_dir_.AppendASCII("api_test") |
166 .AppendASCII("lazy_background_page") | 411 .AppendASCII("lazy_background_page") |
167 .AppendASCII("broadcast_event")); | 412 .AppendASCII("broadcast_event")); |
168 ASSERT_TRUE(extension.get()); | 413 ASSERT_TRUE(extension.get()); |
169 | 414 |
(...skipping 17 matching lines...) Expand all Loading... | |
187 pm->OnNetworkRequestDone(frame_host, 1); | 432 pm->OnNetworkRequestDone(frame_host, 1); |
188 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); | 433 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); |
189 | 434 |
190 // Simulate only a request completion for this ID and ensure it doesn't result | 435 // Simulate only a request completion for this ID and ensure it doesn't result |
191 // in keepalive decrement. | 436 // in keepalive decrement. |
192 pm->OnNetworkRequestDone(frame_host, 2); | 437 pm->OnNetworkRequestDone(frame_host, 2); |
193 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); | 438 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); |
194 } | 439 } |
195 | 440 |
196 } // namespace extensions | 441 } // namespace extensions |
OLD | NEW |