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/callback.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/run_loop.h" | |
10 #include "base/strings/stringprintf.h" | |
7 #include "chrome/browser/extensions/browser_action_test_util.h" | 11 #include "chrome/browser/extensions/browser_action_test_util.h" |
8 #include "chrome/browser/extensions/extension_browsertest.h" | 12 #include "chrome/browser/extensions/extension_browsertest.h" |
9 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
14 #include "chrome/browser/extensions/test_extension_dir.h" | |
10 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 15 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
16 #include "chrome/common/extensions/extension_process_policy.h" | |
11 #include "chrome/test/base/in_process_browser_test.h" | 17 #include "chrome/test/base/in_process_browser_test.h" |
12 #include "chrome/test/base/ui_test_utils.h" | 18 #include "chrome/test/base/ui_test_utils.h" |
13 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
20 #include "content/public/browser/render_frame_host.h" | |
14 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
22 #include "content/public/test/browser_test_utils.h" | |
15 #include "content/public/test/test_utils.h" | 23 #include "content/public/test/test_utils.h" |
24 #include "extensions/common/value_builder.h" | |
25 #include "extensions/test/background_page_watcher.h" | |
26 #include "extensions/test/extension_test_message_listener.h" | |
16 #include "net/dns/mock_host_resolver.h" | 27 #include "net/dns/mock_host_resolver.h" |
17 #include "net/test/embedded_test_server/embedded_test_server.h" | 28 #include "net/test/embedded_test_server/embedded_test_server.h" |
18 | 29 |
19 namespace extensions { | 30 namespace extensions { |
20 | 31 |
32 namespace { | |
33 | |
34 void AddFrameToSet(std::set<content::RenderFrameHost*>* frames, | |
35 content::RenderFrameHost* rfh) { | |
36 if (rfh->IsRenderFrameLive()) | |
37 frames->insert(rfh); | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 // Takes a snapshot of all frames upon construction. When Wait is called, a | |
43 // MessageLoop is created and Quit when all previously recorded frames are | |
44 // either present in the tab, or deleted. | |
45 class NavigationCompletedObserver : public content::WebContentsObserver { | |
46 public: | |
47 explicit NavigationCompletedObserver(content::WebContents* web_contents) | |
48 : content::WebContentsObserver(web_contents), | |
49 web_contents_(web_contents), | |
50 message_loop_runner_(new content::MessageLoopRunner) { | |
51 web_contents->ForEachFrame( | |
52 base::Bind(&AddFrameToSet, base::Unretained(&frames_))); | |
53 } | |
54 | |
55 void Wait() { | |
56 if (!AreAllFramesInTab()) | |
57 message_loop_runner_->Run(); | |
58 } | |
59 | |
60 void RenderFrameDeleted(content::RenderFrameHost* rfh) override { | |
61 if (frames_.erase(rfh) != 0 && message_loop_runner_->loop_running() && | |
62 AreAllFramesInTab()) | |
63 message_loop_runner_->Quit(); | |
64 } | |
65 | |
66 private: | |
67 bool AreAllFramesInTab() { | |
Devlin
2015/12/01 00:58:20
nit: please document this method.
robwu
2015/12/01 17:19:57
Done.
| |
68 std::set<content::RenderFrameHost*> current_frames; | |
69 web_contents_->ForEachFrame( | |
70 base::Bind(&AddFrameToSet, base::Unretained(¤t_frames))); | |
71 for (content::RenderFrameHost* frame : frames_) { | |
72 if (current_frames.find(frame) == current_frames.end()) | |
73 return false; | |
74 } | |
75 return true; | |
76 } | |
77 | |
78 content::WebContents* web_contents_; | |
ncarter (slow)
2015/11/30 22:56:46
You don't need this; WebContentsObserver has a web
robwu
2015/12/01 00:45:26
Done.
| |
79 std::set<content::RenderFrameHost*> frames_; | |
80 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
Devlin
2015/12/01 00:58:20
nit: DISALLOW_COPY_AND_ASSIGN
robwu
2015/12/01 17:19:57
Done.
| |
81 }; | |
82 | |
21 // Exists as a browser test because ExtensionHosts are hard to create without | 83 // Exists as a browser test because ExtensionHosts are hard to create without |
22 // a real browser. | 84 // a real browser. |
23 typedef ExtensionBrowserTest ProcessManagerBrowserTest; | 85 class ProcessManagerBrowserTest : public ExtensionBrowserTest { |
86 public: | |
87 // Create an extension with web-accessible frames and an optional background | |
88 // page. | |
89 const Extension* CreateExtension(const std::string& name, | |
90 bool has_background_process) { | |
91 scoped_ptr<TestExtensionDir> dir(new TestExtensionDir); | |
Devlin
2015/12/01 00:58:20
nitty nit: prefer explicit construction (i.e., "ne
robwu
2015/12/01 17:19:57
Done.
| |
92 | |
93 DictionaryBuilder manifest; | |
94 manifest.Set("name", name) | |
95 .Set("version", "1") | |
96 .Set("manifest_version", 2) | |
97 // To allow ExecuteScript* to work. | |
98 .Set("content_security_policy", | |
99 "script-src 'self' 'unsafe-eval'; object-src 'self'") | |
100 .Set("web_accessible_resources", ListBuilder().Append("*")); | |
101 | |
102 if (has_background_process) { | |
103 manifest.Set("background", DictionaryBuilder().Set("page", "bg.html")); | |
104 dir->WriteFile(FILE_PATH_LITERAL("bg.html"), | |
105 "<iframe id=bgframe src=empty.html></iframe>"); | |
106 } | |
107 | |
108 dir->WriteFile(FILE_PATH_LITERAL("blank_iframe.html"), | |
109 "<iframe id=frame0 src='about:blank'></iframe>"); | |
110 | |
111 dir->WriteFile(FILE_PATH_LITERAL("srcdoc_iframe.html"), | |
112 "<iframe id=frame0 srcdoc='Hello world'></iframe>"); | |
113 | |
114 dir->WriteFile(FILE_PATH_LITERAL("two_iframes.html"), | |
115 "<iframe id=frame1 src=empty.html></iframe>" | |
116 "<iframe id=frame2 src=empty.html></iframe>"); | |
117 | |
118 dir->WriteFile(FILE_PATH_LITERAL("empty.html"), ""); | |
119 | |
120 dir->WriteManifest(manifest.ToJSON()); | |
121 | |
122 const Extension* extension = LoadExtension(dir->unpacked_path()); | |
123 EXPECT_TRUE(extension); | |
124 temp_dirs_.push_back(dir.Pass()); | |
125 return extension; | |
126 } | |
127 | |
128 // ui_test_utils::NavigateToURL sometimes returns too early: It returns as | |
129 // soon as the StopLoading notification has been triggered. This does not | |
130 // imply that RenderFrameDeleted was called, so the test may continue too | |
131 // early and fail when ProcessManager::GetAllFrames() returns too many frames | |
132 // (namely frames that are in the process of being deleted). | |
133 void NavigateToURL(const GURL& url) { | |
134 NavigationCompletedObserver observer( | |
135 browser()->tab_strip_model()->GetActiveWebContents()); | |
136 | |
137 ui_test_utils::NavigateToURL(browser(), url); | |
138 | |
139 // Wait until the last RenderFrameHosts are deleted. This wait doesn't take | |
140 // long. | |
141 observer.Wait(); | |
142 } | |
143 | |
144 void NavigateIframeToURLAndWait(content::WebContents* web_contents, | |
145 const std::string iframe_id, | |
146 const GURL& url) { | |
147 // This is an improved version of content::NavigateIframeToURL. Unlike the | |
148 // other method, this does actually wait until the load of all child frames | |
149 // completes. | |
150 std::string script = base::StringPrintf( | |
151 "var frame = document.getElementById('%s');" | |
152 "frame.onload = frame.onerror = function(event) {" | |
153 " frame.onload = frame.onerror = null;" | |
154 " domAutomationController.send(event.type === 'load');" | |
155 "};" | |
156 "frame.src = '%s';", | |
157 iframe_id.c_str(), url.spec().c_str()); | |
158 bool is_loaded = false; | |
159 EXPECT_TRUE(ExecuteScriptAndExtractBool(web_contents, script, &is_loaded)); | |
160 EXPECT_TRUE(is_loaded); | |
161 } | |
162 | |
163 size_t IfExtensionsIsolated(size_t if_enabled, size_t if_disabled) { | |
164 return content::AreAllSitesIsolatedForTesting() || | |
165 IsIsolateExtensionsEnabled() ? if_enabled : if_disabled; | |
166 } | |
167 | |
168 private: | |
169 std::vector<scoped_ptr<TestExtensionDir>> temp_dirs_; | |
Devlin
2015/12/01 00:58:20
nit: DISALLOW_COPY_AND_ASSIGN
robwu
2015/12/01 17:19:57
Done.
robwu
2015/12/01 23:19:57
I added this and compilation failed, so I've rever
| |
170 }; | |
24 | 171 |
25 // Test that basic extension loading creates the appropriate ExtensionHosts | 172 // Test that basic extension loading creates the appropriate ExtensionHosts |
26 // and background pages. | 173 // and background pages. |
27 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, | 174 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, |
28 ExtensionHostCreation) { | 175 ExtensionHostCreation) { |
29 ProcessManager* pm = ProcessManager::Get(profile()); | 176 ProcessManager* pm = ProcessManager::Get(profile()); |
30 | 177 |
31 // We start with no background hosts. | 178 // We start with no background hosts. |
32 ASSERT_EQ(0u, pm->background_hosts().size()); | 179 ASSERT_EQ(0u, pm->background_hosts().size()); |
33 ASSERT_EQ(0u, pm->GetAllFrames().size()); | 180 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 = | 297 content::WebContents* extension_web_contents = |
151 content::WebContents::FromRenderFrameHost( | 298 content::WebContents::FromRenderFrameHost( |
152 *pm->GetRenderFrameHostsForExtension(extension->id()).begin()); | 299 *pm->GetRenderFrameHostsForExtension(extension->id()).begin()); |
153 EXPECT_TRUE(extension_web_contents->GetSiteInstance() != | 300 EXPECT_TRUE(extension_web_contents->GetSiteInstance() != |
154 tab_web_contents->GetSiteInstance()); | 301 tab_web_contents->GetSiteInstance()); |
155 EXPECT_TRUE(pm->GetSiteInstanceForURL(extension->url()) != | 302 EXPECT_TRUE(pm->GetSiteInstanceForURL(extension->url()) != |
156 tab_web_contents->GetSiteInstance()); | 303 tab_web_contents->GetSiteInstance()); |
157 EXPECT_TRUE(pm->GetBackgroundHostForExtension(extension->id())); | 304 EXPECT_TRUE(pm->GetBackgroundHostForExtension(extension->id())); |
158 } | 305 } |
159 | 306 |
307 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, NoBackgroundPage) { | |
308 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | |
309 | |
310 ProcessManager* pm = ProcessManager::Get(profile()); | |
311 const Extension* extension = | |
312 LoadExtension(test_data_dir_.AppendASCII("api_test") | |
313 .AppendASCII("messaging") | |
Devlin
2015/12/01 00:58:20
indentation looks off - was this git cl formatted?
robwu
2015/12/01 17:19:57
No. I've now ran git cl format and the indention i
| |
314 .AppendASCII("connect_nobackground")); | |
315 ASSERT_TRUE(extension); | |
316 | |
317 // The extension has no background page. | |
318 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
319 | |
320 // Start in a non-extension process, then navigate to an extension process. | |
321 NavigateToURL(embedded_test_server()->GetURL("/empty.html")); | |
322 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
323 | |
324 const GURL extension_url = extension->url().Resolve("manifest.json"); | |
325 NavigateToURL(extension_url); | |
326 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
327 | |
328 NavigateToURL(GURL("about:blank")); | |
329 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
330 | |
331 ui_test_utils::NavigateToURLWithDisposition( | |
332 browser(), extension_url, NEW_FOREGROUND_TAB, | |
333 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); | |
334 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); | |
335 } | |
336 | |
337 // Tests whether frames are correctly classified. Non-extension frames should | |
338 // never appear in the list. Top-level extension frames should always appear. | |
339 // Child extension frames should only appear if it is hosted in an extension | |
340 // process (i.e. if the top-level frame is an extension page, or if OOP frames | |
341 // are enabled for extensions). | |
342 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, FrameClassification) { | |
343 const Extension* extension1 = CreateExtension("Extension 1", false); | |
344 const Extension* extension2 = CreateExtension("Extension 2", true); | |
345 embedded_test_server()->ServeFilesFromDirectory(extension1->path()); | |
346 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | |
347 | |
348 const GURL ext1_parent_url(extension1->url().Resolve("two_iframes.html")); | |
Devlin
2015/12/01 00:58:20
nit: for consts like these, I usually prefer kExt1
robwu
2015/12/01 17:19:57
Done.
| |
349 const GURL ext1_empty_url(extension1->url().Resolve("empty.html")); | |
350 const GURL ext2_parent_url(extension2->url().Resolve("two_iframes.html")); | |
351 const GURL ext2_empty_url(extension2->url().Resolve("empty.html")); | |
352 | |
353 ProcessManager* pm = ProcessManager::Get(profile()); | |
354 BackgroundPageWatcher(pm, extension2).WaitForOpen(); | |
355 | |
356 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
357 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
358 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
Devlin
2015/12/01 00:58:20
For this, it would probably be nice to include com
robwu
2015/12/01 17:19:57
Done.
| |
359 | |
360 ExecuteScriptInBackgroundPageNoWait(extension2->id(), | |
361 "setTimeout(window.close, 0)"); | |
362 BackgroundPageWatcher(pm, extension2).WaitForClose(); | |
363 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
364 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
Devlin
2015/12/01 00:58:20
nit: unless GetAllFrames() is supremely busted, th
robwu
2015/12/01 17:19:57
In the current implementation it does not matter,
| |
365 | |
366 NavigateToURL(embedded_test_server()->GetURL("/two_iframes.html")); | |
367 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
368 | |
369 content::WebContents* tab = | |
370 browser()->tab_strip_model()->GetActiveWebContents(); | |
371 | |
372 // Tests extension frames in non-extension page. | |
373 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
374 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
375 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
376 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); | |
377 | |
378 NavigateIframeToURLAndWait(tab, "frame2", ext2_empty_url); | |
379 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
380 pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
381 EXPECT_EQ(IfExtensionsIsolated(2, 0), pm->GetAllFrames().size()); | |
382 | |
383 // Tests non-extension page in extension frame | |
384 NavigateToURL(ext1_parent_url); | |
Devlin
2015/12/01 00:58:20
Here, too, comments would be nice. It's hard to k
robwu
2015/12/01 17:19:57
Done.
| |
385 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
386 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
387 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
388 | |
389 NavigateIframeToURLAndWait(tab, "frame1", | |
390 embedded_test_server()->GetURL("/empty.html")); | |
391 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
392 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
393 | |
394 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
395 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
396 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
397 | |
398 // Load a frame from another extension. | |
399 NavigateIframeToURLAndWait(tab, "frame1", ext2_empty_url); | |
400 EXPECT_EQ(IfExtensionsIsolated(3, 2), pm->GetAllFrames().size()); | |
401 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
402 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
403 pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
404 | |
405 // Destroy all existing frames by navigating to another extension. | |
406 NavigateToURL(extension2->url().Resolve("empty.html")); | |
407 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
408 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
409 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
410 | |
411 // Test about:blank and about:srcdoc child frames. | |
412 NavigateToURL(extension2->url().Resolve("srcdoc_iframe.html")); | |
413 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
414 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
415 | |
416 NavigateToURL(extension2->url().Resolve("blank_iframe.html")); | |
417 EXPECT_EQ(2u, pm->GetAllFrames().size()); | |
418 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
419 | |
420 // Test nested frames (same extension). | |
421 NavigateToURL(ext2_parent_url); | |
422 EXPECT_EQ(3u, pm->GetAllFrames().size()); | |
423 EXPECT_EQ(3u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
424 | |
425 NavigateIframeToURLAndWait(tab, "frame1", ext2_parent_url); | |
426 EXPECT_EQ(5u, pm->GetAllFrames().size()); | |
427 EXPECT_EQ(5u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
428 | |
429 // The extension frame from the other extension should not be classified as an | |
430 // extension (unless out-of-process frames are enabled). | |
431 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
432 EXPECT_EQ(IfExtensionsIsolated(3, 2), pm->GetAllFrames().size()); | |
433 EXPECT_EQ(IfExtensionsIsolated(1, 0), | |
434 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
435 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
436 | |
437 NavigateIframeToURLAndWait(tab, "frame2", ext1_parent_url); | |
438 EXPECT_EQ(IfExtensionsIsolated(5, 1), pm->GetAllFrames().size()); | |
439 EXPECT_EQ(IfExtensionsIsolated(4, 0), | |
440 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
441 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
442 | |
443 // Crash tab where the top-level frame is an extension frame. | |
444 content::CrashTab(tab); | |
445 EXPECT_EQ(0u, pm->GetAllFrames().size()); | |
446 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
447 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension2->id()).size()); | |
448 | |
449 // Now load an extension page and a non-extension page... | |
450 ui_test_utils::NavigateToURLWithDisposition( | |
451 browser(), ext1_empty_url, NEW_BACKGROUND_TAB, | |
452 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); | |
453 NavigateToURL(embedded_test_server()->GetURL("/two_iframes.html")); | |
454 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
455 | |
456 // ... load an extension frame in the non-extension process | |
457 NavigateIframeToURLAndWait(tab, "frame1", ext1_empty_url); | |
458 EXPECT_EQ(IfExtensionsIsolated(2, 1), | |
459 pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
460 | |
461 // ... and take down the tab. The extension process is not part of the tab, | |
462 // so it should be kept alive (minus the frames that died). | |
463 content::CrashTab(tab); | |
464 EXPECT_EQ(1u, pm->GetAllFrames().size()); | |
465 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension1->id()).size()); | |
466 } | |
467 | |
160 // Verify correct keepalive count behavior on network request events. | 468 // Verify correct keepalive count behavior on network request events. |
161 // Regression test for http://crbug.com/535716. | 469 // Regression test for http://crbug.com/535716. |
162 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, KeepaliveOnNetworkRequest) { | 470 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, KeepaliveOnNetworkRequest) { |
163 // Load an extension with a lazy background page. | 471 // Load an extension with a lazy background page. |
164 scoped_refptr<const Extension> extension = | 472 scoped_refptr<const Extension> extension = |
165 LoadExtension(test_data_dir_.AppendASCII("api_test") | 473 LoadExtension(test_data_dir_.AppendASCII("api_test") |
166 .AppendASCII("lazy_background_page") | 474 .AppendASCII("lazy_background_page") |
167 .AppendASCII("broadcast_event")); | 475 .AppendASCII("broadcast_event")); |
168 ASSERT_TRUE(extension.get()); | 476 ASSERT_TRUE(extension.get()); |
169 | 477 |
(...skipping 17 matching lines...) Expand all Loading... | |
187 pm->OnNetworkRequestDone(frame_host, 1); | 495 pm->OnNetworkRequestDone(frame_host, 1); |
188 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); | 496 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); |
189 | 497 |
190 // Simulate only a request completion for this ID and ensure it doesn't result | 498 // Simulate only a request completion for this ID and ensure it doesn't result |
191 // in keepalive decrement. | 499 // in keepalive decrement. |
192 pm->OnNetworkRequestDone(frame_host, 2); | 500 pm->OnNetworkRequestDone(frame_host, 2); |
193 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); | 501 EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); |
194 } | 502 } |
195 | 503 |
196 } // namespace extensions | 504 } // namespace extensions |
OLD | NEW |