blob: fea468a0b64e5a06e088b91209542ed949d7a12d [file] [log] [blame]
[email protected]c333e792012-01-06 16:57:391// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]3a8eecb2010-04-22 23:56:302// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]ce7f62e32010-08-10 23:43:595#include "base/utf_string_conversions.h"
[email protected]3a8eecb2010-04-22 23:56:306#include "chrome/browser/extensions/extension_apitest.h"
7#include "chrome/browser/extensions/extension_host.h"
[email protected]6f371442011-11-09 06:45:468#include "chrome/browser/extensions/extension_service.h"
9#include "chrome/browser/extensions/process_map.h"
[email protected]8ecad5e2010-12-02 21:18:3310#include "chrome/browser/profiles/profile.h"
[email protected]7b5dc002010-11-16 23:08:1011#include "chrome/browser/ui/browser.h"
[email protected]71b73f02011-04-06 15:57:2912#include "chrome/browser/ui/browser_list.h"
[email protected]d55c2382011-08-18 23:10:3613#include "chrome/browser/ui/browser_window.h"
[email protected]ae673742011-08-24 19:48:3714#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
[email protected]3a8eecb2010-04-22 23:56:3015#include "chrome/common/chrome_switches.h"
[email protected]814a7bf0f2011-08-13 05:30:5916#include "chrome/common/extensions/extension.h"
[email protected]c2f36e3a2011-12-14 01:27:1917#include "chrome/common/extensions/extension_file_util.h"
[email protected]36a5c4c2011-12-14 16:34:5018#include "chrome/common/string_ordinal.h"
[email protected]af44e7fb2011-07-29 18:32:3219#include "chrome/test/base/ui_test_utils.h"
[email protected]ad23a092011-12-28 07:02:0420#include "content/public/browser/navigation_entry.h"
[email protected]ad50def52011-10-19 23:17:0721#include "content/public/browser/notification_service.h"
[email protected]c333e792012-01-06 16:57:3922#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3323#include "content/public/browser/render_view_host.h"
[email protected]6acde6352012-01-04 16:52:2024#include "content/public/browser/web_contents.h"
[email protected]88aae972011-12-16 01:14:1825#include "content/test/test_navigation_observer.h"
[email protected]3a8eecb2010-04-22 23:56:3026#include "net/base/mock_host_resolver.h"
27
[email protected]c5eed492012-01-04 17:07:5028using content::NavigationController;
[email protected]eaabba22012-03-07 15:02:1129using content::RenderViewHost;
[email protected]4ca15302012-01-03 05:53:2030using content::WebContents;
31
[email protected]3a8eecb2010-04-22 23:56:3032// Simulates a page calling window.open on an URL, and waits for the navigation.
33static void WindowOpenHelper(Browser* browser,
[email protected]12ea9b272010-08-24 11:31:4034 RenderViewHost* opener_host,
35 const GURL& url,
36 bool newtab_process_should_equal_opener) {
[email protected]3114db2c2011-09-12 20:09:0537 ui_test_utils::WindowedNotificationObserver observer(
[email protected]ad50def52011-10-19 23:17:0738 content::NOTIFICATION_LOAD_STOP,
39 content::NotificationService::AllSources());
[email protected]9fabbf72010-09-30 21:50:0540 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(
41 opener_host, L"", L"window.open('" + UTF8ToWide(url.spec()) + L"');"));
[email protected]3a8eecb2010-04-22 23:56:3042
[email protected]12ea9b272010-08-24 11:31:4043 // The above window.open call is not user-initiated, it will create
44 // a popup window instead of a new tab in current window.
45 // Now the active tab in last active window should be the new tab.
46 Browser* last_active_browser = BrowserList::GetLastActive();
47 EXPECT_TRUE(last_active_browser);
[email protected]4ca15302012-01-03 05:53:2048 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]12ea9b272010-08-24 11:31:4049 EXPECT_TRUE(newtab);
[email protected]3114db2c2011-09-12 20:09:0550 observer.Wait();
[email protected]36fc0392011-12-25 03:59:5151 EXPECT_EQ(url, newtab->GetController().GetLastCommittedEntry()->GetURL());
[email protected]12ea9b272010-08-24 11:31:4052 if (newtab_process_should_equal_opener)
[email protected]9f76c1e2012-03-05 15:15:5853 EXPECT_EQ(opener_host->GetProcess(), newtab->GetRenderProcessHost());
[email protected]12ea9b272010-08-24 11:31:4054 else
[email protected]9f76c1e2012-03-05 15:15:5855 EXPECT_NE(opener_host->GetProcess(), newtab->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:3056}
57
58// Simulates a page navigating itself to an URL, and waits for the navigation.
[email protected]6acde6352012-01-04 16:52:2059static void NavigateTabHelper(WebContents* contents, const GURL& url) {
[email protected]3a8eecb2010-04-22 23:56:3060 bool result = false;
[email protected]3114db2c2011-09-12 20:09:0561 ui_test_utils::WindowedNotificationObserver observer(
62 content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:0763 content::NotificationService::AllSources());
[email protected]9fabbf72010-09-30 21:50:0564 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:5265 contents->GetRenderViewHost(), L"",
[email protected]d38f83f2010-04-30 23:25:5766 L"window.addEventListener('unload', function() {"
67 L" window.domAutomationController.send(true);"
68 L"}, false);"
69 L"window.location = '" + UTF8ToWide(url.spec()) + L"';",
[email protected]9fabbf72010-09-30 21:50:0570 &result));
[email protected]3a8eecb2010-04-22 23:56:3071 ASSERT_TRUE(result);
[email protected]3114db2c2011-09-12 20:09:0572 observer.Wait();
[email protected]36fc0392011-12-25 03:59:5173 EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
[email protected]3a8eecb2010-04-22 23:56:3074}
75
[email protected]7b54ca02012-03-02 18:06:5376class AppApiTest : public ExtensionApiTest {
77 protected:
78 // Gets the base URL for files for a specific test, making sure that it uses
79 // "localhost" as the hostname, since that is what the extent is declared
80 // as in the test apps manifests.
81 GURL GetTestBaseURL(std::string test_directory) {
82 GURL::Replacements replace_host;
83 std::string host_str("localhost"); // must stay in scope with replace_host
84 replace_host.SetHostStr(host_str);
85 GURL base_url = test_server()->GetURL(
86 "files/extensions/api_test/" + test_directory + "/");
87 return base_url.ReplaceComponents(replace_host);
88 }
89
90 // Pass flags to make testing apps easier.
91 void SetUpCommandLine(CommandLine* command_line) {
92 ExtensionApiTest::SetUpCommandLine(command_line);
93 CommandLine::ForCurrentProcess()->AppendSwitch(
94 switches::kDisablePopupBlocking);
95 CommandLine::ForCurrentProcess()->AppendSwitch(
96 switches::kAllowHTTPBackgroundPage);
97 }
98
99 // Helper function to test that independent tabs of the named app are loaded
100 // into separate processes.
101 void TestAppInstancesHelper(std::string app_name) {
102 LOG(INFO) << "Start of test.";
103
104 extensions::ProcessMap* process_map =
105 browser()->profile()->GetExtensionService()->process_map();
106
107 host_resolver()->AddRule("*", "127.0.0.1");
108 ASSERT_TRUE(test_server()->Start());
109
110 ASSERT_TRUE(LoadExtension(
111 test_data_dir_.AppendASCII(app_name)));
112
113 // Open two tabs in the app, one outside it.
114 GURL base_url = GetTestBaseURL(app_name);
115
116 // Test both opening a URL in a new tab, and opening a tab and then
117 // navigating it. Either way, app tabs should be considered extension
118 // processes, but they have no elevated privileges and thus should not
119 // have WebUI bindings.
120 ui_test_utils::NavigateToURLWithDisposition(
121 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
122 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
123 LOG(INFO) << "Nav 1.";
124 EXPECT_TRUE(process_map->Contains(
125 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
126 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
127
128 ui_test_utils::WindowedNotificationObserver tab_added_observer(
129 content::NOTIFICATION_TAB_ADDED,
130 content::NotificationService::AllSources());
131 browser()->NewTab();
132 tab_added_observer.Wait();
133 LOG(INFO) << "New tab.";
134 ui_test_utils::NavigateToURL(browser(),
135 base_url.Resolve("path2/empty.html"));
136 LOG(INFO) << "Nav 2.";
137 EXPECT_TRUE(process_map->Contains(
138 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
139 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
140
141 // We should have opened 2 new extension tabs. Including the original blank
142 // tab, we now have 3 tabs. The two app tabs should not be in the same
143 // process, since they do not have the background permission. (Thus, we
144 // want to separate them to improve responsiveness.)
145 ASSERT_EQ(3, browser()->tab_count());
146 RenderViewHost* host1 = browser()->GetWebContentsAt(1)->GetRenderViewHost();
147 RenderViewHost* host2 = browser()->GetWebContentsAt(2)->GetRenderViewHost();
[email protected]9f76c1e2012-03-05 15:15:58148 EXPECT_NE(host1->GetProcess(), host2->GetProcess());
[email protected]7b54ca02012-03-02 18:06:53149
150 // Opening tabs with window.open should keep the page in the opener's
151 // process.
152 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
153 WindowOpenHelper(browser(), host1,
154 base_url.Resolve("path1/empty.html"), true);
155 LOG(INFO) << "WindowOpenHelper 1.";
156 WindowOpenHelper(browser(), host2,
157 base_url.Resolve("path2/empty.html"), true);
158 LOG(INFO) << "End of test.";
159 }
160};
161
162// Tests that hosted apps with the background permission get a process-per-app
163// model, since all pages need to be able to script the background page.
[email protected]87c7c292011-10-27 16:16:41164IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
165 LOG(INFO) << "Start of test.";
[email protected]9b600832011-10-26 20:31:59166
[email protected]6f371442011-11-09 06:45:46167 extensions::ProcessMap* process_map =
168 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52169
[email protected]3a8eecb2010-04-22 23:56:30170 host_resolver()->AddRule("*", "127.0.0.1");
[email protected]95409e12010-08-17 20:07:11171 ASSERT_TRUE(test_server()->Start());
[email protected]3a8eecb2010-04-22 23:56:30172
[email protected]cbf4d1912010-08-12 18:24:57173 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
[email protected]3a8eecb2010-04-22 23:56:30174
[email protected]87c7c292011-10-27 16:16:41175 LOG(INFO) << "Loaded extension.";
176
[email protected]cbf4d1912010-08-12 18:24:57177 // Open two tabs in the app, one outside it.
[email protected]118d3122011-08-10 17:09:53178 GURL base_url = GetTestBaseURL("app_process");
[email protected]fe3048872010-10-18 14:58:59179
[email protected]f0e13332011-05-20 22:41:14180 // Test both opening a URL in a new tab, and opening a tab and then navigating
181 // it. Either way, app tabs should be considered extension processes, but
182 // they have no elevated privileges and thus should not have WebUI bindings.
183 ui_test_utils::NavigateToURLWithDisposition(
184 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
185 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46186 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20187 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
188 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41189 LOG(INFO) << "Nav 1.";
190
191 ui_test_utils::NavigateToURLWithDisposition(
192 browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
193 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46194 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20195 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
196 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41197 LOG(INFO) << "Nav 2.";
198
199 ui_test_utils::WindowedNotificationObserver tab_added_observer(
200 content::NOTIFICATION_TAB_ADDED,
201 content::NotificationService::AllSources());
[email protected]cbf4d1912010-08-12 18:24:57202 browser()->NewTab();
[email protected]87c7c292011-10-27 16:16:41203 tab_added_observer.Wait();
204 LOG(INFO) << "New tab.";
[email protected]cbf4d1912010-08-12 18:24:57205 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
[email protected]87c7c292011-10-27 16:16:41206 LOG(INFO) << "Nav 3.";
[email protected]6f371442011-11-09 06:45:46207 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20208 browser()->GetWebContentsAt(3)->GetRenderProcessHost()->GetID()));
209 EXPECT_FALSE(browser()->GetWebContentsAt(3)->GetWebUI());
[email protected]3a8eecb2010-04-22 23:56:30210
[email protected]056ad2a2011-07-12 02:13:55211 // We should have opened 3 new extension tabs. Including the original blank
212 // tab, we now have 4 tabs. Because the app_process app has the background
213 // permission, all of its instances are in the same process. Thus two tabs
214 // should be part of the extension app and grouped in the same process.
[email protected]3a8eecb2010-04-22 23:56:30215 ASSERT_EQ(4, browser()->tab_count());
[email protected]6acde6352012-01-04 16:52:20216 RenderViewHost* host = browser()->GetWebContentsAt(1)->GetRenderViewHost();
[email protected]cbf4d1912010-08-12 18:24:57217
[email protected]9f76c1e2012-03-05 15:15:58218 EXPECT_EQ(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20219 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]9f76c1e2012-03-05 15:15:58220 EXPECT_NE(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20221 browser()->GetWebContentsAt(3)->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:30222
223 // Now let's do the same using window.open. The same should happen.
[email protected]12ea9b272010-08-24 11:31:40224 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
[email protected]cbf4d1912010-08-12 18:24:57225 WindowOpenHelper(browser(), host,
[email protected]12ea9b272010-08-24 11:31:40226 base_url.Resolve("path1/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41227 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]cbf4d1912010-08-12 18:24:57228 WindowOpenHelper(browser(), host,
[email protected]12ea9b272010-08-24 11:31:40229 base_url.Resolve("path2/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41230 LOG(INFO) << "WindowOpenHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15231 // TODO(creis): This should open in a new process (i.e., false for the last
232 // argument), but we temporarily avoid swapping processes away from an app
233 // until we're able to support cross-process postMessage calls.
234 // See crbug.com/59285.
[email protected]cbf4d1912010-08-12 18:24:57235 WindowOpenHelper(browser(), host,
[email protected]361a5f1f2011-10-05 20:11:15236 base_url.Resolve("path3/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41237 LOG(INFO) << "WindowOpenHelper 3.";
[email protected]3a8eecb2010-04-22 23:56:30238
239 // Now let's have these pages navigate, into or out of the extension web
240 // extent. They should switch processes.
[email protected]9a1e6d42010-04-26 22:29:36241 const GURL& app_url(base_url.Resolve("path1/empty.html"));
242 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]6acde6352012-01-04 16:52:20243 NavigateTabHelper(browser()->GetWebContentsAt(2), non_app_url);
[email protected]87c7c292011-10-27 16:16:41244 LOG(INFO) << "NavigateTabHelper 1.";
[email protected]6acde6352012-01-04 16:52:20245 NavigateTabHelper(browser()->GetWebContentsAt(3), app_url);
[email protected]87c7c292011-10-27 16:16:41246 LOG(INFO) << "NavigateTabHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15247 // TODO(creis): This should swap out of the app's process (i.e., EXPECT_NE),
248 // but we temporarily avoid swapping away from an app in case the window
249 // tries to send a postMessage to the app. See crbug.com/59285.
[email protected]9f76c1e2012-03-05 15:15:58250 EXPECT_EQ(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20251 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]9f76c1e2012-03-05 15:15:58252 EXPECT_EQ(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20253 browser()->GetWebContentsAt(3)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04254
255 // If one of the popup tabs navigates back to the app, window.opener should
256 // be valid.
[email protected]6acde6352012-01-04 16:52:20257 NavigateTabHelper(browser()->GetWebContentsAt(6), app_url);
[email protected]87c7c292011-10-27 16:16:41258 LOG(INFO) << "NavigateTabHelper 3.";
[email protected]9f76c1e2012-03-05 15:15:58259 EXPECT_EQ(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20260 browser()->GetWebContentsAt(6)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04261 bool windowOpenerValid = false;
262 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]6acde6352012-01-04 16:52:20263 browser()->GetWebContentsAt(6)->GetRenderViewHost(), L"",
[email protected]08e94b82010-12-15 22:51:04264 L"window.domAutomationController.send(window.opener != null)",
265 &windowOpenerValid));
266 ASSERT_TRUE(windowOpenerValid);
[email protected]87c7c292011-10-27 16:16:41267
268 LOG(INFO) << "End of test.";
[email protected]3a8eecb2010-04-22 23:56:30269}
[email protected]faf407b2011-01-05 01:24:32270
[email protected]056ad2a2011-07-12 02:13:55271// Test that hosted apps without the background permission use a process per app
272// instance model, such that separate instances are in separate processes.
[email protected]87c7c292011-10-27 16:16:41273IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessInstances) {
[email protected]7b54ca02012-03-02 18:06:53274 TestAppInstancesHelper("app_process_instances");
275}
[email protected]87c7c292011-10-27 16:16:41276
[email protected]7b54ca02012-03-02 18:06:53277// Test that hosted apps with the background permission but that set
278// allow_js_access to false also use a process per app instance model.
279// Separate instances should be in separate processes.
280IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessBackgroundInstances) {
281 TestAppInstancesHelper("app_process_background_instances");
[email protected]056ad2a2011-07-12 02:13:55282}
283
[email protected]15877ca2011-11-18 22:40:52284// Tests that bookmark apps do not use the app process model and are treated
285// like normal web pages instead. http://crbug.com/104636.
[email protected]c2f36e3a2011-12-14 01:27:19286IN_PROC_BROWSER_TEST_F(AppApiTest, BookmarkAppGetsNormalProcess) {
[email protected]c2f36e3a2011-12-14 01:27:19287 ExtensionService* service = browser()->profile()->GetExtensionService();
288 extensions::ProcessMap* process_map = service->process_map();
[email protected]15877ca2011-11-18 22:40:52289
290 host_resolver()->AddRule("*", "127.0.0.1");
291 ASSERT_TRUE(test_server()->Start());
[email protected]15877ca2011-11-18 22:40:52292 GURL base_url = GetTestBaseURL("app_process");
293
[email protected]c2f36e3a2011-12-14 01:27:19294 // Load an app as a bookmark app.
295 std::string error;
296 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
297 test_data_dir_.AppendASCII("app_process"),
298 Extension::LOAD,
299 Extension::FROM_BOOKMARK,
300 &error));
[email protected]36a5c4c2011-12-14 16:34:50301 service->OnExtensionInstalled(extension, false,
302 StringOrdinal::CreateInitialOrdinal());
[email protected]c2f36e3a2011-12-14 01:27:19303 ASSERT_TRUE(extension.get());
304 ASSERT_TRUE(extension->from_bookmark());
305
[email protected]15877ca2011-11-18 22:40:52306 // Test both opening a URL in a new tab, and opening a tab and then navigating
307 // it. Either way, bookmark app tabs should be considered normal processes
308 // with no elevated privileges and no WebUI bindings.
309 ui_test_utils::NavigateToURLWithDisposition(
310 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
311 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
312 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20313 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
314 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52315
316 ui_test_utils::WindowedNotificationObserver tab_added_observer(
317 content::NOTIFICATION_TAB_ADDED,
318 content::NotificationService::AllSources());
319 browser()->NewTab();
320 tab_added_observer.Wait();
321 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
322 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20323 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
324 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52325
326 // We should have opened 2 new bookmark app tabs. Including the original blank
327 // tab, we now have 3 tabs. Because normal pages use the
328 // process-per-site-instance model, each should be in its own process.
329 ASSERT_EQ(3, browser()->tab_count());
[email protected]6acde6352012-01-04 16:52:20330 RenderViewHost* host = browser()->GetWebContentsAt(1)->GetRenderViewHost();
[email protected]9f76c1e2012-03-05 15:15:58331 EXPECT_NE(host->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20332 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52333
334 // Now let's do the same using window.open. The same should happen.
335 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
336 WindowOpenHelper(browser(), host,
337 base_url.Resolve("path1/empty.html"), true);
338 WindowOpenHelper(browser(), host,
339 base_url.Resolve("path2/empty.html"), true);
340
341 // Now let's have a tab navigate out of and back into the app's web
342 // extent. Neither navigation should switch processes.
343 const GURL& app_url(base_url.Resolve("path1/empty.html"));
344 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]6acde6352012-01-04 16:52:20345 RenderViewHost* host2 = browser()->GetWebContentsAt(2)->GetRenderViewHost();
346 NavigateTabHelper(browser()->GetWebContentsAt(2), non_app_url);
[email protected]9f76c1e2012-03-05 15:15:58347 EXPECT_EQ(host2->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20348 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
349 NavigateTabHelper(browser()->GetWebContentsAt(2), app_url);
[email protected]9f76c1e2012-03-05 15:15:58350 EXPECT_EQ(host2->GetProcess(),
[email protected]6acde6352012-01-04 16:52:20351 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52352}
353
[email protected]faf407b2011-01-05 01:24:32354// Tests that app process switching works properly in the following scenario:
355// 1. navigate to a page1 in the app
356// 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
357// 3. page2 redirects back to a page in the app
358// The final navigation should end up in the app process.
359// See http://crbug.com/61757
[email protected]678d7022011-12-30 10:18:54360// This test doesn't complete on WebKit Win (dbg). See crbug.com/108853.
[email protected]eea84c02012-01-25 06:15:25361#if defined(OS_WIN) && !defined(NDEBUG)
[email protected]c374f8a82011-12-01 00:45:08362#define MAYBE_AppProcessRedirectBack DISABLED_AppProcessRedirectBack
363#else
364#define MAYBE_AppProcessRedirectBack AppProcessRedirectBack
365#endif
366IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessRedirectBack) {
[email protected]faf407b2011-01-05 01:24:32367 host_resolver()->AddRule("*", "127.0.0.1");
368 ASSERT_TRUE(test_server()->Start());
369
370 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
371
372 // Open two tabs in the app.
[email protected]118d3122011-08-10 17:09:53373 GURL base_url = GetTestBaseURL("app_process");
[email protected]faf407b2011-01-05 01:24:32374
375 browser()->NewTab();
376 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
377 browser()->NewTab();
[email protected]4ad5d77d2011-12-03 02:00:48378 // Wait until the second tab finishes its redirect train (3 hops).
379 // 1. We navigate to redirect.html
380 // 2. Renderer navigates and finishes, counting as a load stop.
381 // 3. Renderer issues the meta refresh to navigate to server-redirect.
382 // 4. Renderer is now in a "provisional load", waiting for navigation to
383 // complete.
384 // 5. Browser sees a redirect response from server-redirect to empty.html, and
385 // transfers that to a new navigation, using RequestTransferURL.
386 // 6. We navigate to empty.html.
387 // 7. Renderer is still in a provisional load to server-redirect, so that is
388 // cancelled, and counts as a load stop
389 // 8. Renderer navigates to empty.html, and finishes loading, counting as the
390 // third load stop
[email protected]4ad5d77d2011-12-03 02:00:48391 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
392 browser(), base_url.Resolve("path1/redirect.html"), 3);
[email protected]faf407b2011-01-05 01:24:32393
394 // 3 tabs, including the initial about:blank. The last 2 should be the same
395 // process.
396 ASSERT_EQ(3, browser()->tab_count());
[email protected]089e8c332011-01-06 21:37:29397 EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
[email protected]6acde6352012-01-04 16:52:20398 browser()->GetWebContentsAt(2)->GetController().
[email protected]36fc0392011-12-25 03:59:51399 GetLastCommittedEntry()->GetURL().path());
[email protected]6acde6352012-01-04 16:52:20400 EXPECT_EQ(browser()->GetWebContentsAt(1)->GetRenderProcessHost(),
401 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]faf407b2011-01-05 01:24:32402}
[email protected]d292d8a2011-05-25 03:47:11403
404// Ensure that reloading a URL after installing or uninstalling it as an app
405// correctly swaps the process. (http://crbug.com/80621)
[email protected]11535962012-02-09 21:02:10406IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcess) {
[email protected]6f371442011-11-09 06:45:46407 extensions::ProcessMap* process_map =
408 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52409
[email protected]d292d8a2011-05-25 03:47:11410 host_resolver()->AddRule("*", "127.0.0.1");
411 ASSERT_TRUE(test_server()->Start());
412
413 // The app under test acts on URLs whose host is "localhost",
414 // so the URLs we navigate to must have host "localhost".
[email protected]118d3122011-08-10 17:09:53415 GURL base_url = GetTestBaseURL("app_process");
[email protected]d292d8a2011-05-25 03:47:11416
417 // Load an app URL before loading the app.
418 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6acde6352012-01-04 16:52:20419 WebContents* contents = browser()->GetWebContentsAt(0);
[email protected]6f371442011-11-09 06:45:46420 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52421 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11422
[email protected]8d3132f62011-10-12 07:13:42423 // Load app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11424 const Extension* app =
425 LoadExtension(test_data_dir_.AppendASCII("app_process"));
426 ASSERT_TRUE(app);
427 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46428 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52429 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11430
[email protected]8d3132f62011-10-12 07:13:42431 // Disable app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11432 DisableExtension(app->id());
433 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46434 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52435 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11436
[email protected]8d3132f62011-10-12 07:13:42437 // Enable app and reload the page.
438 EnableExtension(app->id());
439 ui_test_utils::WindowedNotificationObserver reload_observer(
440 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50441 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20442 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56443 GetController()));
[email protected]8d3132f62011-10-12 07:13:42444 browser()->Reload(CURRENT_TAB);
445 reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46446 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52447 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42448
449 // Disable app and reload the page.
450 DisableExtension(app->id());
451 ui_test_utils::WindowedNotificationObserver reload_observer2(
452 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50453 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20454 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56455 GetController()));
[email protected]8d3132f62011-10-12 07:13:42456 browser()->Reload(CURRENT_TAB);
457 reload_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46458 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52459 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42460
[email protected]d292d8a2011-05-25 03:47:11461 // Enable app and reload via JavaScript.
462 EnableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42463 ui_test_utils::WindowedNotificationObserver js_reload_observer(
464 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50465 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20466 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56467 GetController()));
[email protected]151a63d2011-12-20 22:32:52468 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]d292d8a2011-05-25 03:47:11469 L"", L"location.reload();"));
[email protected]8d3132f62011-10-12 07:13:42470 js_reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46471 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52472 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11473
474 // Disable app and reload via JavaScript.
475 DisableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42476 ui_test_utils::WindowedNotificationObserver js_reload_observer2(
477 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50478 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20479 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56480 GetController()));
[email protected]151a63d2011-12-20 22:32:52481 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]bcd904482012-02-01 01:54:22482 L"", L"location = location;"));
[email protected]8d3132f62011-10-12 07:13:42483 js_reload_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46484 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52485 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11486}
[email protected]118d3122011-08-10 17:09:53487
[email protected]118d3122011-08-10 17:09:53488// Tests that if we have a non-app process (path3/container.html) that has an
489// iframe with a URL in the app's extent (path1/iframe.html), then opening a
490// link from that iframe to a new window to a URL in the app's extent (path1/
491// empty.html) results in the new window being in an app process. See
492// http://crbug.com/89272 for more details.
493IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
[email protected]6f371442011-11-09 06:45:46494 extensions::ProcessMap* process_map =
495 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52496
[email protected]118d3122011-08-10 17:09:53497 host_resolver()->AddRule("*", "127.0.0.1");
498 ASSERT_TRUE(test_server()->Start());
499
500 GURL base_url = GetTestBaseURL("app_process");
501
502 // Load app and start URL (not in the app).
503 const Extension* app =
504 LoadExtension(test_data_dir_.AppendASCII("app_process"));
505 ASSERT_TRUE(app);
506 ui_test_utils::NavigateToURLWithDisposition(
507 browser(),
508 base_url.Resolve("path3/container.html"),
509 CURRENT_TAB,
510 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION |
511 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
[email protected]6f371442011-11-09 06:45:46512 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20513 browser()->GetWebContentsAt(0)->GetRenderProcessHost()->GetID()));
[email protected]118d3122011-08-10 17:09:53514
515 // Wait for popup window to appear.
516 GURL app_url = base_url.Resolve("path1/empty.html");
517 Browser* last_active_browser = BrowserList::GetLastActive();
518 EXPECT_TRUE(last_active_browser);
519 ASSERT_NE(browser(), last_active_browser);
[email protected]4ca15302012-01-03 05:53:20520 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]118d3122011-08-10 17:09:53521 EXPECT_TRUE(newtab);
[email protected]f5fa20e2011-12-21 22:35:56522 if (!newtab->GetController().GetLastCommittedEntry() ||
[email protected]36fc0392011-12-25 03:59:51523 newtab->GetController().GetLastCommittedEntry()->GetURL() != app_url) {
[email protected]160f17f12011-10-19 00:40:00524 // TODO(gbillock): This still looks racy. Need to make a custom
525 // observer to intercept new window creation and then look for
526 // NAV_ENTRY_COMMITTED on the new tab there.
527 ui_test_utils::WindowedNotificationObserver observer(
528 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
[email protected]c5eed492012-01-04 17:07:50529 content::Source<NavigationController>(&(newtab->GetController())));
[email protected]160f17f12011-10-19 00:40:00530 observer.Wait();
531 }
[email protected]118d3122011-08-10 17:09:53532
533 // Popup window should be in the app's process.
[email protected]6f371442011-11-09 06:45:46534 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20535 last_active_browser->GetWebContentsAt(0)->GetRenderProcessHost()->
[email protected]f3b1a082011-11-18 00:34:30536 GetID()));
[email protected]118d3122011-08-10 17:09:53537}
[email protected]a09add52011-08-12 03:59:23538
[email protected]88aae972011-12-16 01:14:18539// Tests that if an extension launches an app via chrome.tabs.create with an URL
540// that's not in the app's extent but that redirects to it, we still end up with
541// an app process. See http://crbug.com/99349 for more details.
542IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromExtension) {
543 host_resolver()->AddRule("*", "127.0.0.1");
544 ASSERT_TRUE(StartTestServer());
545
546 LoadExtension(test_data_dir_.AppendASCII("app_process"));
547 const Extension* launcher =
548 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
549
550 // There should be three navigations by the time the app page is loaded.
551 // 1. The extension launcher page.
552 // 2. The URL that the extension launches, which redirects.
553 // 3. The app's URL.
554 TestNavigationObserver test_navigation_observer(
555 content::NotificationService::AllSources(),
556 NULL,
557 3);
558
559 // Load the launcher extension, which should launch the app.
560 ui_test_utils::NavigateToURLWithDisposition(
561 browser(),
562 launcher->GetResourceURL("main.html"),
563 CURRENT_TAB,
564 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
565
566 // Wait for app tab to be created and loaded.
567 test_navigation_observer.WaitForObservation(
568 base::Bind(&ui_test_utils::RunMessageLoop),
569 base::Bind(&MessageLoop::Quit,
570 base::Unretained(MessageLoopForUI::current())));
571
572 // App has loaded, and chrome.app.isInstalled should be true.
573 bool is_installed = false;
574 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]4ca15302012-01-03 05:53:20575 browser()->GetSelectedWebContents()->GetRenderViewHost(), L"",
[email protected]88aae972011-12-16 01:14:18576 L"window.domAutomationController.send(chrome.app.isInstalled)",
577 &is_installed));
578 ASSERT_TRUE(is_installed);
579}
580
[email protected]d55c2382011-08-18 23:10:36581// Tests that if we have an app process (path1/container.html) with a non-app
582// iframe (path3/iframe.html), then opening a link from that iframe to a new
583// window to a same-origin non-app URL (path3/empty.html) should keep the window
584// in the app process.
585// This is in contrast to OpenAppFromIframe, since here the popup will not be
586// missing special permissions and should be scriptable from the iframe.
587// See http://crbug.com/92669 for more details.
588IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
[email protected]6f371442011-11-09 06:45:46589 extensions::ProcessMap* process_map =
590 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52591
[email protected]d55c2382011-08-18 23:10:36592 host_resolver()->AddRule("*", "127.0.0.1");
593 ASSERT_TRUE(test_server()->Start());
594
595 GURL base_url = GetTestBaseURL("app_process");
596
597 // Load app and start URL (in the app).
598 const Extension* app =
599 LoadExtension(test_data_dir_.AppendASCII("app_process"));
600 ASSERT_TRUE(app);
[email protected]160f17f12011-10-19 00:40:00601 ui_test_utils::WindowedNotificationObserver observer(
602 content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:07603 content::NotificationService::AllSources());
[email protected]d55c2382011-08-18 23:10:36604 ui_test_utils::NavigateToURLWithDisposition(
605 browser(),
606 base_url.Resolve("path1/container.html"),
607 CURRENT_TAB,
608 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION |
609 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
[email protected]f3b1a082011-11-18 00:34:30610 content::RenderProcessHost* process =
[email protected]6acde6352012-01-04 16:52:20611 browser()->GetWebContentsAt(0)->GetRenderProcessHost();
[email protected]f3b1a082011-11-18 00:34:30612 EXPECT_TRUE(process_map->Contains(process->GetID()));
[email protected]d55c2382011-08-18 23:10:36613
614 // Wait for popup window to appear. The new Browser may not have been
615 // added with SetLastActive, in which case we need to show it first.
616 // This is necessary for popup windows without a cross-site transition.
617 if (browser() == BrowserList::GetLastActive()) {
618 // Grab the second window and show it.
619 ASSERT_TRUE(BrowserList::size() == 2);
620 Browser* popup_browser = *(++BrowserList::begin());
621 popup_browser->window()->Show();
622 }
623 Browser* last_active_browser = BrowserList::GetLastActive();
624 EXPECT_TRUE(last_active_browser);
625 ASSERT_NE(browser(), last_active_browser);
[email protected]4ca15302012-01-03 05:53:20626 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]d55c2382011-08-18 23:10:36627 EXPECT_TRUE(newtab);
628 GURL non_app_url = base_url.Resolve("path3/empty.html");
[email protected]160f17f12011-10-19 00:40:00629 observer.Wait();
[email protected]d55c2382011-08-18 23:10:36630
631 // Popup window should be in the app's process.
[email protected]f3b1a082011-11-18 00:34:30632 content::RenderProcessHost* popup_process =
[email protected]6acde6352012-01-04 16:52:20633 last_active_browser->GetWebContentsAt(0)->GetRenderProcessHost();
[email protected]d55c2382011-08-18 23:10:36634 EXPECT_EQ(process, popup_process);
635}
636
[email protected]a344b762012-03-16 18:53:49637// http://crbug.com/118502
638#if defined(OS_MACOSX) || defined(OS_LINUX)
639#define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
640#else
641#define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
642#endif
643IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
[email protected]6f371442011-11-09 06:45:46644 extensions::ProcessMap* process_map =
645 browser()->profile()->GetExtensionService()->process_map();
646
[email protected]a09add52011-08-12 03:59:23647 host_resolver()->AddRule("*", "127.0.0.1");
648 ASSERT_TRUE(test_server()->Start());
649
650 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
651
652 GURL base_url = GetTestBaseURL("app_process");
653
654 // Load the app, chrome.app.isInstalled should be true.
655 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6acde6352012-01-04 16:52:20656 WebContents* contents = browser()->GetWebContentsAt(0);
[email protected]6f371442011-11-09 06:45:46657 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52658 contents->GetRenderProcessHost()->GetID()));
[email protected]a09add52011-08-12 03:59:23659 bool is_installed = false;
660 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52661 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23662 L"window.domAutomationController.send(chrome.app.isInstalled)",
663 &is_installed));
664 ASSERT_TRUE(is_installed);
665
666 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
[email protected]4ca15302012-01-03 05:53:20667 ui_test_utils::CrashTab(browser()->GetSelectedWebContents());
[email protected]ae673742011-08-24 19:48:37668 ui_test_utils::WindowedNotificationObserver observer(
669 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50670 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20671 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56672 GetController()));
[email protected]a09add52011-08-12 03:59:23673 browser()->Reload(CURRENT_TAB);
[email protected]ae673742011-08-24 19:48:37674 observer.Wait();
[email protected]a09add52011-08-12 03:59:23675 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52676 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23677 L"window.domAutomationController.send(chrome.app.isInstalled)",
678 &is_installed));
679 ASSERT_TRUE(is_installed);
680}