blob: c1de458fb384edb1827f709a3c0d17413cb3ff9c [file] [log] [blame]
[email protected]71b73f02011-04-06 15:57:291// Copyright (c) 2011 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]a035dfda2011-03-02 01:01:4920#include "content/browser/renderer_host/render_view_host.h"
[email protected]ad23a092011-12-28 07:02:0421#include "content/public/browser/navigation_entry.h"
[email protected]ad50def52011-10-19 23:17:0722#include "content/public/browser/notification_service.h"
[email protected]6acde6352012-01-04 16:52:2023#include "content/public/browser/web_contents.h"
[email protected]88aae972011-12-16 01:14:1824#include "content/test/test_navigation_observer.h"
[email protected]3a8eecb2010-04-22 23:56:3025#include "net/base/mock_host_resolver.h"
26
[email protected]c5eed492012-01-04 17:07:5027using content::NavigationController;
[email protected]4ca15302012-01-03 05:53:2028using content::WebContents;
29
[email protected]3a8eecb2010-04-22 23:56:3030class AppApiTest : public ExtensionApiTest {
[email protected]118d3122011-08-10 17:09:5331 protected:
32 // Gets the base URL for files for a specific test, making sure that it uses
33 // "localhost" as the hostname, since that is what the extent is declared
34 // as in the test apps manifests.
35 GURL GetTestBaseURL(std::string test_directory) {
36 GURL::Replacements replace_host;
37 std::string host_str("localhost"); // must stay in scope with replace_host
38 replace_host.SetHostStr(host_str);
39 GURL base_url = test_server()->GetURL(
40 "files/extensions/api_test/" + test_directory + "/");
41 return base_url.ReplaceComponents(replace_host);
42 }
[email protected]3a8eecb2010-04-22 23:56:3043};
44
45// Simulates a page calling window.open on an URL, and waits for the navigation.
46static void WindowOpenHelper(Browser* browser,
[email protected]12ea9b272010-08-24 11:31:4047 RenderViewHost* opener_host,
48 const GURL& url,
49 bool newtab_process_should_equal_opener) {
[email protected]3114db2c2011-09-12 20:09:0550 ui_test_utils::WindowedNotificationObserver observer(
[email protected]ad50def52011-10-19 23:17:0751 content::NOTIFICATION_LOAD_STOP,
52 content::NotificationService::AllSources());
[email protected]9fabbf72010-09-30 21:50:0553 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(
54 opener_host, L"", L"window.open('" + UTF8ToWide(url.spec()) + L"');"));
[email protected]3a8eecb2010-04-22 23:56:3055
[email protected]12ea9b272010-08-24 11:31:4056 // The above window.open call is not user-initiated, it will create
57 // a popup window instead of a new tab in current window.
58 // Now the active tab in last active window should be the new tab.
59 Browser* last_active_browser = BrowserList::GetLastActive();
60 EXPECT_TRUE(last_active_browser);
[email protected]4ca15302012-01-03 05:53:2061 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]12ea9b272010-08-24 11:31:4062 EXPECT_TRUE(newtab);
[email protected]3114db2c2011-09-12 20:09:0563 observer.Wait();
[email protected]36fc0392011-12-25 03:59:5164 EXPECT_EQ(url, newtab->GetController().GetLastCommittedEntry()->GetURL());
[email protected]12ea9b272010-08-24 11:31:4065 if (newtab_process_should_equal_opener)
[email protected]151a63d2011-12-20 22:32:5266 EXPECT_EQ(opener_host->process(), newtab->GetRenderProcessHost());
[email protected]12ea9b272010-08-24 11:31:4067 else
[email protected]151a63d2011-12-20 22:32:5268 EXPECT_NE(opener_host->process(), newtab->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:3069}
70
71// Simulates a page navigating itself to an URL, and waits for the navigation.
[email protected]6acde6352012-01-04 16:52:2072static void NavigateTabHelper(WebContents* contents, const GURL& url) {
[email protected]3a8eecb2010-04-22 23:56:3073 bool result = false;
[email protected]3114db2c2011-09-12 20:09:0574 ui_test_utils::WindowedNotificationObserver observer(
75 content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:0776 content::NotificationService::AllSources());
[email protected]9fabbf72010-09-30 21:50:0577 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:5278 contents->GetRenderViewHost(), L"",
[email protected]d38f83f2010-04-30 23:25:5779 L"window.addEventListener('unload', function() {"
80 L" window.domAutomationController.send(true);"
81 L"}, false);"
82 L"window.location = '" + UTF8ToWide(url.spec()) + L"';",
[email protected]9fabbf72010-09-30 21:50:0583 &result));
[email protected]3a8eecb2010-04-22 23:56:3084 ASSERT_TRUE(result);
[email protected]3114db2c2011-09-12 20:09:0585 observer.Wait();
[email protected]36fc0392011-12-25 03:59:5186 EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
[email protected]3a8eecb2010-04-22 23:56:3087}
88
[email protected]87c7c292011-10-27 16:16:4189IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
90 LOG(INFO) << "Start of test.";
[email protected]9b600832011-10-26 20:31:5991
[email protected]12ea9b272010-08-24 11:31:4092 CommandLine::ForCurrentProcess()->AppendSwitch(
93 switches::kDisablePopupBlocking);
94
[email protected]6f371442011-11-09 06:45:4695 extensions::ProcessMap* process_map =
96 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:5297
[email protected]3a8eecb2010-04-22 23:56:3098 host_resolver()->AddRule("*", "127.0.0.1");
[email protected]95409e12010-08-17 20:07:1199 ASSERT_TRUE(test_server()->Start());
[email protected]3a8eecb2010-04-22 23:56:30100
[email protected]cbf4d1912010-08-12 18:24:57101 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
[email protected]3a8eecb2010-04-22 23:56:30102
[email protected]87c7c292011-10-27 16:16:41103 LOG(INFO) << "Loaded extension.";
104
[email protected]cbf4d1912010-08-12 18:24:57105 // Open two tabs in the app, one outside it.
[email protected]118d3122011-08-10 17:09:53106 GURL base_url = GetTestBaseURL("app_process");
[email protected]fe3048872010-10-18 14:58:59107
[email protected]f0e13332011-05-20 22:41:14108 // Test both opening a URL in a new tab, and opening a tab and then navigating
109 // it. Either way, app tabs should be considered extension processes, but
110 // they have no elevated privileges and thus should not have WebUI bindings.
111 ui_test_utils::NavigateToURLWithDisposition(
112 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
113 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46114 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20115 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
116 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41117 LOG(INFO) << "Nav 1.";
118
119 ui_test_utils::NavigateToURLWithDisposition(
120 browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
121 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46122 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20123 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
124 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41125 LOG(INFO) << "Nav 2.";
126
127 ui_test_utils::WindowedNotificationObserver tab_added_observer(
128 content::NOTIFICATION_TAB_ADDED,
129 content::NotificationService::AllSources());
[email protected]cbf4d1912010-08-12 18:24:57130 browser()->NewTab();
[email protected]87c7c292011-10-27 16:16:41131 tab_added_observer.Wait();
132 LOG(INFO) << "New tab.";
[email protected]cbf4d1912010-08-12 18:24:57133 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
[email protected]87c7c292011-10-27 16:16:41134 LOG(INFO) << "Nav 3.";
[email protected]6f371442011-11-09 06:45:46135 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20136 browser()->GetWebContentsAt(3)->GetRenderProcessHost()->GetID()));
137 EXPECT_FALSE(browser()->GetWebContentsAt(3)->GetWebUI());
[email protected]3a8eecb2010-04-22 23:56:30138
[email protected]056ad2a2011-07-12 02:13:55139 // We should have opened 3 new extension tabs. Including the original blank
140 // tab, we now have 4 tabs. Because the app_process app has the background
141 // permission, all of its instances are in the same process. Thus two tabs
142 // should be part of the extension app and grouped in the same process.
[email protected]3a8eecb2010-04-22 23:56:30143 ASSERT_EQ(4, browser()->tab_count());
[email protected]6acde6352012-01-04 16:52:20144 RenderViewHost* host = browser()->GetWebContentsAt(1)->GetRenderViewHost();
[email protected]cbf4d1912010-08-12 18:24:57145
146 EXPECT_EQ(host->process(),
[email protected]6acde6352012-01-04 16:52:20147 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]cbf4d1912010-08-12 18:24:57148 EXPECT_NE(host->process(),
[email protected]6acde6352012-01-04 16:52:20149 browser()->GetWebContentsAt(3)->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:30150
151 // Now let's do the same using window.open. The same should happen.
[email protected]12ea9b272010-08-24 11:31:40152 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
[email protected]cbf4d1912010-08-12 18:24:57153 WindowOpenHelper(browser(), host,
[email protected]12ea9b272010-08-24 11:31:40154 base_url.Resolve("path1/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41155 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]cbf4d1912010-08-12 18:24:57156 WindowOpenHelper(browser(), host,
[email protected]12ea9b272010-08-24 11:31:40157 base_url.Resolve("path2/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41158 LOG(INFO) << "WindowOpenHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15159 // TODO(creis): This should open in a new process (i.e., false for the last
160 // argument), but we temporarily avoid swapping processes away from an app
161 // until we're able to support cross-process postMessage calls.
162 // See crbug.com/59285.
[email protected]cbf4d1912010-08-12 18:24:57163 WindowOpenHelper(browser(), host,
[email protected]361a5f1f2011-10-05 20:11:15164 base_url.Resolve("path3/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41165 LOG(INFO) << "WindowOpenHelper 3.";
[email protected]3a8eecb2010-04-22 23:56:30166
167 // Now let's have these pages navigate, into or out of the extension web
168 // extent. They should switch processes.
[email protected]9a1e6d42010-04-26 22:29:36169 const GURL& app_url(base_url.Resolve("path1/empty.html"));
170 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]6acde6352012-01-04 16:52:20171 NavigateTabHelper(browser()->GetWebContentsAt(2), non_app_url);
[email protected]87c7c292011-10-27 16:16:41172 LOG(INFO) << "NavigateTabHelper 1.";
[email protected]6acde6352012-01-04 16:52:20173 NavigateTabHelper(browser()->GetWebContentsAt(3), app_url);
[email protected]87c7c292011-10-27 16:16:41174 LOG(INFO) << "NavigateTabHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15175 // TODO(creis): This should swap out of the app's process (i.e., EXPECT_NE),
176 // but we temporarily avoid swapping away from an app in case the window
177 // tries to send a postMessage to the app. See crbug.com/59285.
178 EXPECT_EQ(host->process(),
[email protected]6acde6352012-01-04 16:52:20179 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]cbf4d1912010-08-12 18:24:57180 EXPECT_EQ(host->process(),
[email protected]6acde6352012-01-04 16:52:20181 browser()->GetWebContentsAt(3)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04182
183 // If one of the popup tabs navigates back to the app, window.opener should
184 // be valid.
[email protected]6acde6352012-01-04 16:52:20185 NavigateTabHelper(browser()->GetWebContentsAt(6), app_url);
[email protected]87c7c292011-10-27 16:16:41186 LOG(INFO) << "NavigateTabHelper 3.";
[email protected]08e94b82010-12-15 22:51:04187 EXPECT_EQ(host->process(),
[email protected]6acde6352012-01-04 16:52:20188 browser()->GetWebContentsAt(6)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04189 bool windowOpenerValid = false;
190 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]6acde6352012-01-04 16:52:20191 browser()->GetWebContentsAt(6)->GetRenderViewHost(), L"",
[email protected]08e94b82010-12-15 22:51:04192 L"window.domAutomationController.send(window.opener != null)",
193 &windowOpenerValid));
194 ASSERT_TRUE(windowOpenerValid);
[email protected]87c7c292011-10-27 16:16:41195
196 LOG(INFO) << "End of test.";
[email protected]3a8eecb2010-04-22 23:56:30197}
[email protected]faf407b2011-01-05 01:24:32198
[email protected]056ad2a2011-07-12 02:13:55199// Test that hosted apps without the background permission use a process per app
200// instance model, such that separate instances are in separate processes.
[email protected]87c7c292011-10-27 16:16:41201IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessInstances) {
202 LOG(INFO) << "Start of test.";
203
[email protected]056ad2a2011-07-12 02:13:55204 CommandLine::ForCurrentProcess()->AppendSwitch(
205 switches::kDisablePopupBlocking);
206
[email protected]6f371442011-11-09 06:45:46207 extensions::ProcessMap* process_map =
208 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52209
[email protected]056ad2a2011-07-12 02:13:55210 host_resolver()->AddRule("*", "127.0.0.1");
211 ASSERT_TRUE(test_server()->Start());
212
213 ASSERT_TRUE(LoadExtension(
214 test_data_dir_.AppendASCII("app_process_instances")));
215
216 // Open two tabs in the app, one outside it.
[email protected]118d3122011-08-10 17:09:53217 GURL base_url = GetTestBaseURL("app_process_instances");
[email protected]056ad2a2011-07-12 02:13:55218
219 // Test both opening a URL in a new tab, and opening a tab and then navigating
220 // it. Either way, app tabs should be considered extension processes, but
221 // they have no elevated privileges and thus should not have WebUI bindings.
222 ui_test_utils::NavigateToURLWithDisposition(
223 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
224 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]87c7c292011-10-27 16:16:41225 LOG(INFO) << "Nav 1.";
[email protected]6f371442011-11-09 06:45:46226 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20227 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
228 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41229
230 ui_test_utils::WindowedNotificationObserver tab_added_observer(
231 content::NOTIFICATION_TAB_ADDED,
232 content::NotificationService::AllSources());
[email protected]056ad2a2011-07-12 02:13:55233 browser()->NewTab();
[email protected]87c7c292011-10-27 16:16:41234 tab_added_observer.Wait();
235 LOG(INFO) << "New tab.";
[email protected]056ad2a2011-07-12 02:13:55236 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
[email protected]87c7c292011-10-27 16:16:41237 LOG(INFO) << "Nav 2.";
[email protected]6f371442011-11-09 06:45:46238 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20239 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
240 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
[email protected]056ad2a2011-07-12 02:13:55241
242 // We should have opened 2 new extension tabs. Including the original blank
243 // tab, we now have 3 tabs. The two app tabs should not be in the same
244 // process, since they do not have the background permission. (Thus, we want
245 // to separate them to improve responsiveness.)
246 ASSERT_EQ(3, browser()->tab_count());
[email protected]6acde6352012-01-04 16:52:20247 RenderViewHost* host1 = browser()->GetWebContentsAt(1)->GetRenderViewHost();
248 RenderViewHost* host2 = browser()->GetWebContentsAt(2)->GetRenderViewHost();
[email protected]056ad2a2011-07-12 02:13:55249 EXPECT_NE(host1->process(), host2->process());
250
251 // Opening tabs with window.open should keep the page in the opener's process.
252 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
253 WindowOpenHelper(browser(), host1,
254 base_url.Resolve("path1/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41255 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]056ad2a2011-07-12 02:13:55256 WindowOpenHelper(browser(), host2,
257 base_url.Resolve("path2/empty.html"), true);
[email protected]87c7c292011-10-27 16:16:41258 LOG(INFO) << "End of test.";
[email protected]056ad2a2011-07-12 02:13:55259}
260
[email protected]15877ca2011-11-18 22:40:52261// Tests that bookmark apps do not use the app process model and are treated
262// like normal web pages instead. http://crbug.com/104636.
[email protected]c2f36e3a2011-12-14 01:27:19263IN_PROC_BROWSER_TEST_F(AppApiTest, BookmarkAppGetsNormalProcess) {
[email protected]15877ca2011-11-18 22:40:52264 CommandLine::ForCurrentProcess()->AppendSwitch(
265 switches::kDisablePopupBlocking);
266
[email protected]c2f36e3a2011-12-14 01:27:19267 ExtensionService* service = browser()->profile()->GetExtensionService();
268 extensions::ProcessMap* process_map = service->process_map();
[email protected]15877ca2011-11-18 22:40:52269
270 host_resolver()->AddRule("*", "127.0.0.1");
271 ASSERT_TRUE(test_server()->Start());
[email protected]15877ca2011-11-18 22:40:52272 GURL base_url = GetTestBaseURL("app_process");
273
[email protected]c2f36e3a2011-12-14 01:27:19274 // Load an app as a bookmark app.
275 std::string error;
276 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
277 test_data_dir_.AppendASCII("app_process"),
278 Extension::LOAD,
279 Extension::FROM_BOOKMARK,
280 &error));
[email protected]36a5c4c2011-12-14 16:34:50281 service->OnExtensionInstalled(extension, false,
282 StringOrdinal::CreateInitialOrdinal());
[email protected]c2f36e3a2011-12-14 01:27:19283 ASSERT_TRUE(extension.get());
284 ASSERT_TRUE(extension->from_bookmark());
285
[email protected]15877ca2011-11-18 22:40:52286 // Test both opening a URL in a new tab, and opening a tab and then navigating
287 // it. Either way, bookmark app tabs should be considered normal processes
288 // with no elevated privileges and no WebUI bindings.
289 ui_test_utils::NavigateToURLWithDisposition(
290 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
291 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
292 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20293 browser()->GetWebContentsAt(1)->GetRenderProcessHost()->GetID()));
294 EXPECT_FALSE(browser()->GetWebContentsAt(1)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52295
296 ui_test_utils::WindowedNotificationObserver tab_added_observer(
297 content::NOTIFICATION_TAB_ADDED,
298 content::NotificationService::AllSources());
299 browser()->NewTab();
300 tab_added_observer.Wait();
301 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
302 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20303 browser()->GetWebContentsAt(2)->GetRenderProcessHost()->GetID()));
304 EXPECT_FALSE(browser()->GetWebContentsAt(2)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52305
306 // We should have opened 2 new bookmark app tabs. Including the original blank
307 // tab, we now have 3 tabs. Because normal pages use the
308 // process-per-site-instance model, each should be in its own process.
309 ASSERT_EQ(3, browser()->tab_count());
[email protected]6acde6352012-01-04 16:52:20310 RenderViewHost* host = browser()->GetWebContentsAt(1)->GetRenderViewHost();
[email protected]15877ca2011-11-18 22:40:52311 EXPECT_NE(host->process(),
[email protected]6acde6352012-01-04 16:52:20312 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52313
314 // Now let's do the same using window.open. The same should happen.
315 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
316 WindowOpenHelper(browser(), host,
317 base_url.Resolve("path1/empty.html"), true);
318 WindowOpenHelper(browser(), host,
319 base_url.Resolve("path2/empty.html"), true);
320
321 // Now let's have a tab navigate out of and back into the app's web
322 // extent. Neither navigation should switch processes.
323 const GURL& app_url(base_url.Resolve("path1/empty.html"));
324 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]6acde6352012-01-04 16:52:20325 RenderViewHost* host2 = browser()->GetWebContentsAt(2)->GetRenderViewHost();
326 NavigateTabHelper(browser()->GetWebContentsAt(2), non_app_url);
[email protected]15877ca2011-11-18 22:40:52327 EXPECT_EQ(host2->process(),
[email protected]6acde6352012-01-04 16:52:20328 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
329 NavigateTabHelper(browser()->GetWebContentsAt(2), app_url);
[email protected]15877ca2011-11-18 22:40:52330 EXPECT_EQ(host2->process(),
[email protected]6acde6352012-01-04 16:52:20331 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52332}
333
[email protected]faf407b2011-01-05 01:24:32334// Tests that app process switching works properly in the following scenario:
335// 1. navigate to a page1 in the app
336// 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
337// 3. page2 redirects back to a page in the app
338// The final navigation should end up in the app process.
339// See http://crbug.com/61757
[email protected]c374f8a82011-12-01 00:45:08340// This test occasionally timeout on aura. See crbug.com/105957.
[email protected]678d7022011-12-30 10:18:54341// This test doesn't complete on WebKit Win (dbg). See crbug.com/108853.
342#if defined(USE_AURA) || (defined(OS_WIN) && !defined(NDEBUG))
[email protected]c374f8a82011-12-01 00:45:08343#define MAYBE_AppProcessRedirectBack DISABLED_AppProcessRedirectBack
344#else
345#define MAYBE_AppProcessRedirectBack AppProcessRedirectBack
346#endif
347IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessRedirectBack) {
[email protected]faf407b2011-01-05 01:24:32348 CommandLine::ForCurrentProcess()->AppendSwitch(
349 switches::kDisablePopupBlocking);
350
351 host_resolver()->AddRule("*", "127.0.0.1");
352 ASSERT_TRUE(test_server()->Start());
353
354 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
355
356 // Open two tabs in the app.
[email protected]118d3122011-08-10 17:09:53357 GURL base_url = GetTestBaseURL("app_process");
[email protected]faf407b2011-01-05 01:24:32358
359 browser()->NewTab();
360 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
361 browser()->NewTab();
[email protected]4ad5d77d2011-12-03 02:00:48362 // Wait until the second tab finishes its redirect train (3 hops).
363 // 1. We navigate to redirect.html
364 // 2. Renderer navigates and finishes, counting as a load stop.
365 // 3. Renderer issues the meta refresh to navigate to server-redirect.
366 // 4. Renderer is now in a "provisional load", waiting for navigation to
367 // complete.
368 // 5. Browser sees a redirect response from server-redirect to empty.html, and
369 // transfers that to a new navigation, using RequestTransferURL.
370 // 6. We navigate to empty.html.
371 // 7. Renderer is still in a provisional load to server-redirect, so that is
372 // cancelled, and counts as a load stop
373 // 8. Renderer navigates to empty.html, and finishes loading, counting as the
374 // third load stop
[email protected]4ad5d77d2011-12-03 02:00:48375 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
376 browser(), base_url.Resolve("path1/redirect.html"), 3);
[email protected]faf407b2011-01-05 01:24:32377
378 // 3 tabs, including the initial about:blank. The last 2 should be the same
379 // process.
380 ASSERT_EQ(3, browser()->tab_count());
[email protected]089e8c332011-01-06 21:37:29381 EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
[email protected]6acde6352012-01-04 16:52:20382 browser()->GetWebContentsAt(2)->GetController().
[email protected]36fc0392011-12-25 03:59:51383 GetLastCommittedEntry()->GetURL().path());
[email protected]6acde6352012-01-04 16:52:20384 EXPECT_EQ(browser()->GetWebContentsAt(1)->GetRenderProcessHost(),
385 browser()->GetWebContentsAt(2)->GetRenderProcessHost());
[email protected]faf407b2011-01-05 01:24:32386}
[email protected]d292d8a2011-05-25 03:47:11387
388// Ensure that reloading a URL after installing or uninstalling it as an app
389// correctly swaps the process. (http://crbug.com/80621)
[email protected]95df17a2011-11-03 23:03:06390// Disabled until we get a correct fix for 80621. See http://crbug.com/102408.
391IN_PROC_BROWSER_TEST_F(AppApiTest, DISABLED_ReloadIntoAppProcess) {
[email protected]d292d8a2011-05-25 03:47:11392 CommandLine::ForCurrentProcess()->AppendSwitch(
393 switches::kDisablePopupBlocking);
394
[email protected]6f371442011-11-09 06:45:46395 extensions::ProcessMap* process_map =
396 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52397
[email protected]d292d8a2011-05-25 03:47:11398 host_resolver()->AddRule("*", "127.0.0.1");
399 ASSERT_TRUE(test_server()->Start());
400
401 // The app under test acts on URLs whose host is "localhost",
402 // so the URLs we navigate to must have host "localhost".
[email protected]118d3122011-08-10 17:09:53403 GURL base_url = GetTestBaseURL("app_process");
[email protected]d292d8a2011-05-25 03:47:11404
405 // Load an app URL before loading the app.
406 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6acde6352012-01-04 16:52:20407 WebContents* contents = browser()->GetWebContentsAt(0);
[email protected]6f371442011-11-09 06:45:46408 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52409 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11410
[email protected]8d3132f62011-10-12 07:13:42411 // Load app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11412 const Extension* app =
413 LoadExtension(test_data_dir_.AppendASCII("app_process"));
414 ASSERT_TRUE(app);
415 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46416 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52417 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11418
[email protected]8d3132f62011-10-12 07:13:42419 // Disable app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11420 DisableExtension(app->id());
421 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46422 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52423 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11424
[email protected]8d3132f62011-10-12 07:13:42425 // Enable app and reload the page.
426 EnableExtension(app->id());
427 ui_test_utils::WindowedNotificationObserver reload_observer(
428 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50429 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20430 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56431 GetController()));
[email protected]8d3132f62011-10-12 07:13:42432 browser()->Reload(CURRENT_TAB);
433 reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46434 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52435 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42436
437 // Disable app and reload the page.
438 DisableExtension(app->id());
439 ui_test_utils::WindowedNotificationObserver reload_observer2(
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_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46446 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52447 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42448
[email protected]d292d8a2011-05-25 03:47:11449 // Enable app and reload via JavaScript.
450 EnableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42451 ui_test_utils::WindowedNotificationObserver js_reload_observer(
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]151a63d2011-12-20 22:32:52456 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]d292d8a2011-05-25 03:47:11457 L"", L"location.reload();"));
[email protected]8d3132f62011-10-12 07:13:42458 js_reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46459 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52460 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11461
462 // Disable app and reload via JavaScript.
463 DisableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42464 ui_test_utils::WindowedNotificationObserver js_reload_observer2(
465 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50466 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20467 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56468 GetController()));
[email protected]151a63d2011-12-20 22:32:52469 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]d292d8a2011-05-25 03:47:11470 L"", L"location.reload();"));
[email protected]8d3132f62011-10-12 07:13:42471 js_reload_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46472 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52473 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11474}
[email protected]118d3122011-08-10 17:09:53475
[email protected]118d3122011-08-10 17:09:53476// Tests that if we have a non-app process (path3/container.html) that has an
477// iframe with a URL in the app's extent (path1/iframe.html), then opening a
478// link from that iframe to a new window to a URL in the app's extent (path1/
479// empty.html) results in the new window being in an app process. See
480// http://crbug.com/89272 for more details.
481IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
482 CommandLine::ForCurrentProcess()->AppendSwitch(
483 switches::kDisablePopupBlocking);
484
[email protected]6f371442011-11-09 06:45:46485 extensions::ProcessMap* process_map =
486 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52487
[email protected]118d3122011-08-10 17:09:53488 host_resolver()->AddRule("*", "127.0.0.1");
489 ASSERT_TRUE(test_server()->Start());
490
491 GURL base_url = GetTestBaseURL("app_process");
492
493 // Load app and start URL (not in the app).
494 const Extension* app =
495 LoadExtension(test_data_dir_.AppendASCII("app_process"));
496 ASSERT_TRUE(app);
497 ui_test_utils::NavigateToURLWithDisposition(
498 browser(),
499 base_url.Resolve("path3/container.html"),
500 CURRENT_TAB,
501 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION |
502 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
[email protected]6f371442011-11-09 06:45:46503 EXPECT_FALSE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20504 browser()->GetWebContentsAt(0)->GetRenderProcessHost()->GetID()));
[email protected]118d3122011-08-10 17:09:53505
506 // Wait for popup window to appear.
507 GURL app_url = base_url.Resolve("path1/empty.html");
508 Browser* last_active_browser = BrowserList::GetLastActive();
509 EXPECT_TRUE(last_active_browser);
510 ASSERT_NE(browser(), last_active_browser);
[email protected]4ca15302012-01-03 05:53:20511 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]118d3122011-08-10 17:09:53512 EXPECT_TRUE(newtab);
[email protected]f5fa20e2011-12-21 22:35:56513 if (!newtab->GetController().GetLastCommittedEntry() ||
[email protected]36fc0392011-12-25 03:59:51514 newtab->GetController().GetLastCommittedEntry()->GetURL() != app_url) {
[email protected]160f17f12011-10-19 00:40:00515 // TODO(gbillock): This still looks racy. Need to make a custom
516 // observer to intercept new window creation and then look for
517 // NAV_ENTRY_COMMITTED on the new tab there.
518 ui_test_utils::WindowedNotificationObserver observer(
519 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
[email protected]c5eed492012-01-04 17:07:50520 content::Source<NavigationController>(&(newtab->GetController())));
[email protected]160f17f12011-10-19 00:40:00521 observer.Wait();
522 }
[email protected]118d3122011-08-10 17:09:53523
524 // Popup window should be in the app's process.
[email protected]6f371442011-11-09 06:45:46525 EXPECT_TRUE(process_map->Contains(
[email protected]6acde6352012-01-04 16:52:20526 last_active_browser->GetWebContentsAt(0)->GetRenderProcessHost()->
[email protected]f3b1a082011-11-18 00:34:30527 GetID()));
[email protected]118d3122011-08-10 17:09:53528}
[email protected]a09add52011-08-12 03:59:23529
[email protected]88aae972011-12-16 01:14:18530// Tests that if an extension launches an app via chrome.tabs.create with an URL
531// that's not in the app's extent but that redirects to it, we still end up with
532// an app process. See http://crbug.com/99349 for more details.
533IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromExtension) {
534 host_resolver()->AddRule("*", "127.0.0.1");
535 ASSERT_TRUE(StartTestServer());
536
537 LoadExtension(test_data_dir_.AppendASCII("app_process"));
538 const Extension* launcher =
539 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
540
541 // There should be three navigations by the time the app page is loaded.
542 // 1. The extension launcher page.
543 // 2. The URL that the extension launches, which redirects.
544 // 3. The app's URL.
545 TestNavigationObserver test_navigation_observer(
546 content::NotificationService::AllSources(),
547 NULL,
548 3);
549
550 // Load the launcher extension, which should launch the app.
551 ui_test_utils::NavigateToURLWithDisposition(
552 browser(),
553 launcher->GetResourceURL("main.html"),
554 CURRENT_TAB,
555 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
556
557 // Wait for app tab to be created and loaded.
558 test_navigation_observer.WaitForObservation(
559 base::Bind(&ui_test_utils::RunMessageLoop),
560 base::Bind(&MessageLoop::Quit,
561 base::Unretained(MessageLoopForUI::current())));
562
563 // App has loaded, and chrome.app.isInstalled should be true.
564 bool is_installed = false;
565 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]4ca15302012-01-03 05:53:20566 browser()->GetSelectedWebContents()->GetRenderViewHost(), L"",
[email protected]88aae972011-12-16 01:14:18567 L"window.domAutomationController.send(chrome.app.isInstalled)",
568 &is_installed));
569 ASSERT_TRUE(is_installed);
570}
571
[email protected]d55c2382011-08-18 23:10:36572// Tests that if we have an app process (path1/container.html) with a non-app
573// iframe (path3/iframe.html), then opening a link from that iframe to a new
574// window to a same-origin non-app URL (path3/empty.html) should keep the window
575// in the app process.
576// This is in contrast to OpenAppFromIframe, since here the popup will not be
577// missing special permissions and should be scriptable from the iframe.
578// See http://crbug.com/92669 for more details.
579IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
580 CommandLine::ForCurrentProcess()->AppendSwitch(
581 switches::kDisablePopupBlocking);
582
[email protected]6f371442011-11-09 06:45:46583 extensions::ProcessMap* process_map =
584 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52585
[email protected]d55c2382011-08-18 23:10:36586 host_resolver()->AddRule("*", "127.0.0.1");
587 ASSERT_TRUE(test_server()->Start());
588
589 GURL base_url = GetTestBaseURL("app_process");
590
591 // Load app and start URL (in the app).
592 const Extension* app =
593 LoadExtension(test_data_dir_.AppendASCII("app_process"));
594 ASSERT_TRUE(app);
[email protected]160f17f12011-10-19 00:40:00595 ui_test_utils::WindowedNotificationObserver observer(
596 content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:07597 content::NotificationService::AllSources());
[email protected]d55c2382011-08-18 23:10:36598 ui_test_utils::NavigateToURLWithDisposition(
599 browser(),
600 base_url.Resolve("path1/container.html"),
601 CURRENT_TAB,
602 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION |
603 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
[email protected]f3b1a082011-11-18 00:34:30604 content::RenderProcessHost* process =
[email protected]6acde6352012-01-04 16:52:20605 browser()->GetWebContentsAt(0)->GetRenderProcessHost();
[email protected]f3b1a082011-11-18 00:34:30606 EXPECT_TRUE(process_map->Contains(process->GetID()));
[email protected]d55c2382011-08-18 23:10:36607
608 // Wait for popup window to appear. The new Browser may not have been
609 // added with SetLastActive, in which case we need to show it first.
610 // This is necessary for popup windows without a cross-site transition.
611 if (browser() == BrowserList::GetLastActive()) {
612 // Grab the second window and show it.
613 ASSERT_TRUE(BrowserList::size() == 2);
614 Browser* popup_browser = *(++BrowserList::begin());
615 popup_browser->window()->Show();
616 }
617 Browser* last_active_browser = BrowserList::GetLastActive();
618 EXPECT_TRUE(last_active_browser);
619 ASSERT_NE(browser(), last_active_browser);
[email protected]4ca15302012-01-03 05:53:20620 WebContents* newtab = last_active_browser->GetSelectedWebContents();
[email protected]d55c2382011-08-18 23:10:36621 EXPECT_TRUE(newtab);
622 GURL non_app_url = base_url.Resolve("path3/empty.html");
[email protected]160f17f12011-10-19 00:40:00623 observer.Wait();
[email protected]d55c2382011-08-18 23:10:36624
625 // Popup window should be in the app's process.
[email protected]f3b1a082011-11-18 00:34:30626 content::RenderProcessHost* popup_process =
[email protected]6acde6352012-01-04 16:52:20627 last_active_browser->GetWebContentsAt(0)->GetRenderProcessHost();
[email protected]d55c2382011-08-18 23:10:36628 EXPECT_EQ(process, popup_process);
629}
630
[email protected]a09add52011-08-12 03:59:23631IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadAppAfterCrash) {
[email protected]6f371442011-11-09 06:45:46632 extensions::ProcessMap* process_map =
633 browser()->profile()->GetExtensionService()->process_map();
634
[email protected]a09add52011-08-12 03:59:23635 host_resolver()->AddRule("*", "127.0.0.1");
636 ASSERT_TRUE(test_server()->Start());
637
638 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
639
640 GURL base_url = GetTestBaseURL("app_process");
641
642 // Load the app, chrome.app.isInstalled should be true.
643 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6acde6352012-01-04 16:52:20644 WebContents* contents = browser()->GetWebContentsAt(0);
[email protected]6f371442011-11-09 06:45:46645 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52646 contents->GetRenderProcessHost()->GetID()));
[email protected]a09add52011-08-12 03:59:23647 bool is_installed = false;
648 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52649 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23650 L"window.domAutomationController.send(chrome.app.isInstalled)",
651 &is_installed));
652 ASSERT_TRUE(is_installed);
653
654 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
[email protected]4ca15302012-01-03 05:53:20655 ui_test_utils::CrashTab(browser()->GetSelectedWebContents());
[email protected]ae673742011-08-24 19:48:37656 ui_test_utils::WindowedNotificationObserver observer(
657 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50658 content::Source<NavigationController>(
[email protected]6acde6352012-01-04 16:52:20659 &browser()->GetSelectedTabContentsWrapper()->web_contents()->
[email protected]f5fa20e2011-12-21 22:35:56660 GetController()));
[email protected]a09add52011-08-12 03:59:23661 browser()->Reload(CURRENT_TAB);
[email protected]ae673742011-08-24 19:48:37662 observer.Wait();
[email protected]a09add52011-08-12 03:59:23663 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52664 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23665 L"window.domAutomationController.send(chrome.app.isInstalled)",
666 &is_installed));
667 ASSERT_TRUE(is_installed);
668}