Fix build break
[chromium-blink-merge.git] / chrome / browser / renderer_host / render_process_host_chrome_browsertest.cc
blobdf850d13941e4fdab23223c2575a57c135254fc7
1 // Copyright (c) 2012 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.
5 #include "base/command_line.h"
6 #include "chrome/browser/devtools/devtools_window.h"
7 #include "chrome/browser/ui/browser.h"
8 #include "chrome/browser/ui/browser_commands.h"
9 #include "chrome/browser/ui/singleton_tabs.h"
10 #include "chrome/browser/ui/tabs/tab_strip_model.h"
11 #include "chrome/common/chrome_switches.h"
12 #include "chrome/common/url_constants.h"
13 #include "chrome/test/base/in_process_browser_test.h"
14 #include "chrome/test/base/ui_test_utils.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
20 using content::RenderViewHost;
21 using content::RenderWidgetHost;
22 using content::WebContents;
24 namespace {
26 int RenderProcessHostCount() {
27 content::RenderProcessHost::iterator hosts =
28 content::RenderProcessHost::AllHostsIterator();
29 int count = 0;
30 while (!hosts.IsAtEnd()) {
31 if (hosts.GetCurrentValue()->HasConnection())
32 count++;
33 hosts.Advance();
35 return count;
38 RenderViewHost* FindFirstDevToolsHost() {
39 content::RenderProcessHost::iterator hosts =
40 content::RenderProcessHost::AllHostsIterator();
41 for (; !hosts.IsAtEnd(); hosts.Advance()) {
42 content::RenderProcessHost* render_process_host = hosts.GetCurrentValue();
43 DCHECK(render_process_host);
44 if (!render_process_host->HasConnection())
45 continue;
46 content::RenderProcessHost::RenderWidgetHostsIterator iter(
47 render_process_host->GetRenderWidgetHostsIterator());
48 for (; !iter.IsAtEnd(); iter.Advance()) {
49 const RenderWidgetHost* widget = iter.GetCurrentValue();
50 DCHECK(widget);
51 if (!widget || !widget->IsRenderView())
52 continue;
53 RenderViewHost* host =
54 RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
55 WebContents* contents = WebContents::FromRenderViewHost(host);
56 GURL url = contents->GetURL();
57 if (url.SchemeIs(chrome::kChromeDevToolsScheme))
58 return host;
61 return NULL;
64 } // namespace
66 class ChromeRenderProcessHostTest : public InProcessBrowserTest {
67 public:
68 ChromeRenderProcessHostTest() {}
70 // Show a tab, activating the current one if there is one, and wait for
71 // the renderer process to be created or foregrounded, returning the process
72 // handle.
73 base::ProcessHandle ShowSingletonTab(const GURL& page) {
74 chrome::ShowSingletonTab(browser(), page);
75 WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents();
76 CHECK(wc->GetURL() == page);
78 // Ensure that the backgrounding / foregrounding gets a chance to run.
79 content::BrowserThread::PostTaskAndReply(
80 content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
81 base::Bind(&base::DoNothing), MessageLoop::QuitClosure());
82 MessageLoop::current()->Run();
84 return wc->GetRenderProcessHost()->GetHandle();
87 // When we hit the max number of renderers, verify that the way we do process
88 // sharing behaves correctly. In particular, this test is verifying that even
89 // when we hit the max process limit, that renderers of each type will wind up
90 // in a process of that type, even if that means creating a new process.
91 void TestProcessOverflow() {
92 int tab_count = 1;
93 int host_count = 1;
94 WebContents* tab1 = NULL;
95 WebContents* tab2 = NULL;
96 content::RenderProcessHost* rph1 = NULL;
97 content::RenderProcessHost* rph2 = NULL;
98 content::RenderProcessHost* rph3 = NULL;
100 // Change the first tab to be the new tab page (TYPE_WEBUI).
101 GURL newtab(chrome::kChromeUINewTabURL);
102 ui_test_utils::NavigateToURL(browser(), newtab);
103 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
104 tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
105 rph1 = tab1->GetRenderProcessHost();
106 EXPECT_EQ(tab1->GetURL(), newtab);
107 EXPECT_EQ(host_count, RenderProcessHostCount());
109 // Create a new TYPE_TABBED tab. It should be in its own process.
110 GURL page1("data:text/html,hello world1");
112 ui_test_utils::WindowedTabAddedNotificationObserver observer1(
113 content::NotificationService::AllSources());
114 chrome::ShowSingletonTab(browser(), page1);
115 observer1.Wait();
117 tab_count++;
118 host_count++;
119 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
120 tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
121 rph2 = tab1->GetRenderProcessHost();
122 EXPECT_EQ(tab1->GetURL(), page1);
123 EXPECT_EQ(host_count, RenderProcessHostCount());
124 EXPECT_NE(rph1, rph2);
126 // Create another TYPE_TABBED tab. It should share the previous process.
127 GURL page2("data:text/html,hello world2");
128 ui_test_utils::WindowedTabAddedNotificationObserver observer2(
129 content::NotificationService::AllSources());
130 chrome::ShowSingletonTab(browser(), page2);
131 observer2.Wait();
132 tab_count++;
133 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
134 tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
135 EXPECT_EQ(tab2->GetURL(), page2);
136 EXPECT_EQ(host_count, RenderProcessHostCount());
137 EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);
139 // Create another TYPE_WEBUI tab. It should share the process with newtab.
140 // Note: intentionally create this tab after the TYPE_TABBED tabs to
141 // exercise bug 43448 where extension and WebUI tabs could get combined into
142 // normal renderers.
143 GURL history(chrome::kChromeUIHistoryURL);
144 ui_test_utils::WindowedTabAddedNotificationObserver observer3(
145 content::NotificationService::AllSources());
146 chrome::ShowSingletonTab(browser(), history);
147 observer3.Wait();
148 tab_count++;
149 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
150 tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
151 EXPECT_EQ(tab2->GetURL(), GURL(history));
152 EXPECT_EQ(host_count, RenderProcessHostCount());
153 EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);
155 // Create a TYPE_EXTENSION tab. It should be in its own process.
156 // (the bookmark manager is implemented as an extension)
157 GURL bookmarks(chrome::kChromeUIBookmarksURL);
158 ui_test_utils::WindowedTabAddedNotificationObserver observer4(
159 content::NotificationService::AllSources());
160 chrome::ShowSingletonTab(browser(), bookmarks);
161 observer4.Wait();
162 tab_count++;
163 host_count++;
164 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
165 tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
166 rph3 = tab1->GetRenderProcessHost();
167 EXPECT_EQ(tab1->GetURL(), bookmarks);
168 EXPECT_EQ(host_count, RenderProcessHostCount());
169 EXPECT_NE(rph1, rph3);
170 EXPECT_NE(rph2, rph3);
175 class ChromeRenderProcessHostTestWithCommandLine
176 : public ChromeRenderProcessHostTest {
177 protected:
178 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
179 command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1");
183 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessPerTab) {
184 // Set max renderers to 1 to force running out of processes.
185 content::RenderProcessHost::SetMaxRendererProcessCount(1);
187 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
188 parsed_command_line.AppendSwitch(switches::kProcessPerTab);
190 int tab_count = 1;
191 int host_count = 1;
193 // Change the first tab to be the new tab page (TYPE_WEBUI).
194 GURL newtab(chrome::kChromeUINewTabURL);
195 ui_test_utils::NavigateToURL(browser(), newtab);
196 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
197 EXPECT_EQ(host_count, RenderProcessHostCount());
199 // Create a new TYPE_TABBED tab. It should be in its own process.
200 GURL page1("data:text/html,hello world1");
201 ui_test_utils::WindowedTabAddedNotificationObserver observer1(
202 content::NotificationService::AllSources());
203 chrome::ShowSingletonTab(browser(), page1);
204 observer1.Wait();
205 tab_count++;
206 host_count++;
207 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
208 EXPECT_EQ(host_count, RenderProcessHostCount());
210 // Create another TYPE_TABBED tab. It should share the previous process.
211 GURL page2("data:text/html,hello world2");
212 ui_test_utils::WindowedTabAddedNotificationObserver observer2(
213 content::NotificationService::AllSources());
214 chrome::ShowSingletonTab(browser(), page2);
215 observer2.Wait();
216 tab_count++;
217 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
218 EXPECT_EQ(host_count, RenderProcessHostCount());
220 // Create another new tab. It should share the process with the other WebUI.
221 ui_test_utils::WindowedTabAddedNotificationObserver observer3(
222 content::NotificationService::AllSources());
223 chrome::NewTab(browser());
224 observer3.Wait();
225 tab_count++;
226 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
227 EXPECT_EQ(host_count, RenderProcessHostCount());
229 // Create another new tab. It should share the process with the other WebUI.
230 ui_test_utils::WindowedTabAddedNotificationObserver observer4(
231 content::NotificationService::AllSources());
232 chrome::NewTab(browser());
233 observer4.Wait();
234 tab_count++;
235 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
236 EXPECT_EQ(host_count, RenderProcessHostCount());
239 // We don't change process priorities on Mac or Posix because the user lacks the
240 // permission to raise a process' priority even after lowering it.
241 #if defined(OS_WIN) || defined(OS_LINUX)
242 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, Backgrounding) {
243 if (!base::Process::CanBackgroundProcesses()) {
244 LOG(ERROR) << "Can't background processes";
245 return;
247 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
248 parsed_command_line.AppendSwitch(switches::kProcessPerTab);
250 // Change the first tab to be the new tab page (TYPE_WEBUI).
251 GURL newtab(chrome::kChromeUINewTabURL);
252 ui_test_utils::NavigateToURL(browser(), newtab);
254 // Create a new tab. It should be foreground.
255 GURL page1("data:text/html,hello world1");
256 base::ProcessHandle pid1 = ShowSingletonTab(page1);
257 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());
259 // Create another tab. It should be foreground, and the first tab should
260 // now be background.
261 GURL page2("data:text/html,hello world2");
262 base::ProcessHandle pid2 = ShowSingletonTab(page2);
263 EXPECT_NE(pid1, pid2);
264 EXPECT_TRUE(base::Process(pid1).IsProcessBackgrounded());
265 EXPECT_FALSE(base::Process(pid2).IsProcessBackgrounded());
267 // Navigate back to first page. It should be foreground again, and the second
268 // tab should be background.
269 EXPECT_EQ(pid1, ShowSingletonTab(page1));
270 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());
271 EXPECT_TRUE(base::Process(pid2).IsProcessBackgrounded());
273 #endif
275 // TODO(nasko): crbug.com/173137
276 #if defined(OS_WIN)
277 #define MAYBE_ProcessOverflow DISABLED_ProcessOverflow
278 #else
279 #define MAYBE_ProcessOverflow ProcessOverflow
280 #endif
282 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessOverflow) {
283 // Set max renderers to 1 to force running out of processes.
284 content::RenderProcessHost::SetMaxRendererProcessCount(1);
285 TestProcessOverflow();
288 // Variation of the ProcessOverflow test, which is driven through command line
289 // parameter instead of direct function call into the class.
290 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
291 ProcessOverflow) {
292 TestProcessOverflow();
295 // Ensure that DevTools opened to debug DevTools is launched in a separate
296 // process when --process-per-tab is set. See crbug.com/69873.
297 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
298 DevToolsOnSelfInOwnProcessPPT) {
299 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
300 parsed_command_line.AppendSwitch(switches::kProcessPerTab);
302 int tab_count = 1;
303 int host_count = 1;
305 GURL page1("data:text/html,hello world1");
306 ui_test_utils::WindowedTabAddedNotificationObserver observer1(
307 content::NotificationService::AllSources());
308 chrome::ShowSingletonTab(browser(), page1);
309 observer1.Wait();
310 tab_count++;
311 host_count++;
312 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
313 EXPECT_EQ(host_count, RenderProcessHostCount());
315 // DevTools start in docked mode (no new tab), in a separate process.
316 chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
317 host_count++;
318 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
319 EXPECT_EQ(host_count, RenderProcessHostCount());
321 RenderViewHost* devtools = FindFirstDevToolsHost();
322 DCHECK(devtools);
324 // DevTools start in a separate process.
325 DevToolsWindow::ToggleDevToolsWindow(
326 devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
327 host_count++;
328 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
329 EXPECT_EQ(host_count, RenderProcessHostCount());
332 // Ensure that DevTools opened to debug DevTools is launched in a separate
333 // process. See crbug.com/69873.
334 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
335 DevToolsOnSelfInOwnProcess) {
336 int tab_count = 1;
337 int host_count = 1;
339 GURL page1("data:text/html,hello world1");
340 ui_test_utils::WindowedTabAddedNotificationObserver observer1(
341 content::NotificationService::AllSources());
342 chrome::ShowSingletonTab(browser(), page1);
343 observer1.Wait();
344 tab_count++;
345 host_count++;
346 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
347 EXPECT_EQ(host_count, RenderProcessHostCount());
349 // DevTools start in docked mode (no new tab), in a separate process.
350 chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
351 host_count++;
352 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
353 EXPECT_EQ(host_count, RenderProcessHostCount());
355 RenderViewHost* devtools = FindFirstDevToolsHost();
356 DCHECK(devtools);
358 // DevTools start in a separate process.
359 DevToolsWindow::ToggleDevToolsWindow(
360 devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
361 host_count++;
362 EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
363 EXPECT_EQ(host_count, RenderProcessHostCount());