blob: fdc73a7501dc7d64f6b240402ce733263d1d96a5 [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]3a8eecb2010-04-22 23:56:305#include "chrome/browser/extensions/extension_apitest.h"
6#include "chrome/browser/extensions/extension_host.h"
[email protected]6f371442011-11-09 06:45:467#include "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/extensions/process_map.h"
[email protected]8ecad5e2010-12-02 21:18:339#include "chrome/browser/profiles/profile.h"
[email protected]7b5dc002010-11-16 23:08:1010#include "chrome/browser/ui/browser.h"
[email protected]a37d4b02012-06-25 21:56:1011#include "chrome/browser/ui/browser_commands.h"
[email protected]d8748142012-05-16 21:13:4312#include "chrome/browser/ui/browser_finder.h"
[email protected]71b73f02011-04-06 15:57:2913#include "chrome/browser/ui/browser_list.h"
[email protected]52877dbc62012-06-29 22:22:0314#include "chrome/browser/ui/browser_tabstrip.h"
[email protected]d55c2382011-08-18 23:10:3615#include "chrome/browser/ui/browser_window.h"
[email protected]b62084b2012-06-12 01:53:3016#include "chrome/browser/ui/tab_contents/tab_contents.h"
[email protected]884033e2012-04-16 19:38:4217#include "chrome/common/chrome_notification_types.h"
[email protected]3a8eecb2010-04-22 23:56:3018#include "chrome/common/chrome_switches.h"
[email protected]814a7bf0f2011-08-13 05:30:5919#include "chrome/common/extensions/extension.h"
[email protected]c2f36e3a2011-12-14 01:27:1920#include "chrome/common/extensions/extension_file_util.h"
[email protected]36a5c4c2011-12-14 16:34:5021#include "chrome/common/string_ordinal.h"
[email protected]af44e7fb2011-07-29 18:32:3222#include "chrome/test/base/ui_test_utils.h"
[email protected]ad23a092011-12-28 07:02:0423#include "content/public/browser/navigation_entry.h"
[email protected]ad50def52011-10-19 23:17:0724#include "content/public/browser/notification_service.h"
[email protected]c333e792012-01-06 16:57:3925#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3326#include "content/public/browser/render_view_host.h"
[email protected]6acde6352012-01-04 16:52:2027#include "content/public/browser/web_contents.h"
[email protected]5b8ff1c2012-06-02 20:42:2028#include "content/public/test/test_navigation_observer.h"
[email protected]3a8eecb2010-04-22 23:56:3029#include "net/base/mock_host_resolver.h"
30
[email protected]c5eed492012-01-04 17:07:5031using content::NavigationController;
[email protected]eaabba22012-03-07 15:02:1132using content::RenderViewHost;
[email protected]4ca15302012-01-03 05:53:2033using content::WebContents;
[email protected]1c321ee52012-05-21 03:02:3434using extensions::Extension;
[email protected]4ca15302012-01-03 05:53:2035
[email protected]7b54ca02012-03-02 18:06:5336class AppApiTest : public ExtensionApiTest {
37 protected:
38 // Gets the base URL for files for a specific test, making sure that it uses
39 // "localhost" as the hostname, since that is what the extent is declared
40 // as in the test apps manifests.
41 GURL GetTestBaseURL(std::string test_directory) {
42 GURL::Replacements replace_host;
43 std::string host_str("localhost"); // must stay in scope with replace_host
44 replace_host.SetHostStr(host_str);
45 GURL base_url = test_server()->GetURL(
46 "files/extensions/api_test/" + test_directory + "/");
47 return base_url.ReplaceComponents(replace_host);
48 }
49
50 // Pass flags to make testing apps easier.
51 void SetUpCommandLine(CommandLine* command_line) {
52 ExtensionApiTest::SetUpCommandLine(command_line);
53 CommandLine::ForCurrentProcess()->AppendSwitch(
54 switches::kDisablePopupBlocking);
55 CommandLine::ForCurrentProcess()->AppendSwitch(
56 switches::kAllowHTTPBackgroundPage);
57 }
58
59 // Helper function to test that independent tabs of the named app are loaded
60 // into separate processes.
61 void TestAppInstancesHelper(std::string app_name) {
62 LOG(INFO) << "Start of test.";
63
64 extensions::ProcessMap* process_map =
65 browser()->profile()->GetExtensionService()->process_map();
66
67 host_resolver()->AddRule("*", "127.0.0.1");
68 ASSERT_TRUE(test_server()->Start());
69
70 ASSERT_TRUE(LoadExtension(
71 test_data_dir_.AppendASCII(app_name)));
72
73 // Open two tabs in the app, one outside it.
74 GURL base_url = GetTestBaseURL(app_name);
75
76 // Test both opening a URL in a new tab, and opening a tab and then
77 // navigating it. Either way, app tabs should be considered extension
78 // processes, but they have no elevated privileges and thus should not
79 // have WebUI bindings.
80 ui_test_utils::NavigateToURLWithDisposition(
81 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
82 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
83 LOG(INFO) << "Nav 1.";
84 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:0385 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
86 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]7b54ca02012-03-02 18:06:5387
88 ui_test_utils::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:4289 chrome::NOTIFICATION_TAB_ADDED,
[email protected]7b54ca02012-03-02 18:06:5390 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:1091 chrome::NewTab(browser());
[email protected]7b54ca02012-03-02 18:06:5392 tab_added_observer.Wait();
93 LOG(INFO) << "New tab.";
94 ui_test_utils::NavigateToURL(browser(),
95 base_url.Resolve("path2/empty.html"));
96 LOG(INFO) << "Nav 2.";
97 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:0398 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
99 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]7b54ca02012-03-02 18:06:53100
101 // We should have opened 2 new extension tabs. Including the original blank
102 // tab, we now have 3 tabs. The two app tabs should not be in the same
103 // process, since they do not have the background permission. (Thus, we
104 // want to separate them to improve responsiveness.)
105 ASSERT_EQ(3, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03106 WebContents* tab1 = chrome::GetWebContentsAt(browser(), 1);
107 WebContents* tab2 = chrome::GetWebContentsAt(browser(), 2);
[email protected]19da16a92012-05-23 17:11:29108 EXPECT_NE(tab1->GetRenderProcessHost(), tab2->GetRenderProcessHost());
[email protected]7b54ca02012-03-02 18:06:53109
110 // Opening tabs with window.open should keep the page in the opener's
111 // process.
[email protected]d8748142012-05-16 21:13:43112 ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29113 OpenWindow(tab1, base_url.Resolve("path1/empty.html"), true, NULL);
[email protected]7b54ca02012-03-02 18:06:53114 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]19da16a92012-05-23 17:11:29115 OpenWindow(tab2, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]7b54ca02012-03-02 18:06:53116 LOG(INFO) << "End of test.";
117 }
118};
119
120// Tests that hosted apps with the background permission get a process-per-app
121// model, since all pages need to be able to script the background page.
[email protected]19da16a92012-05-23 17:11:29122IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
[email protected]87c7c292011-10-27 16:16:41123 LOG(INFO) << "Start of test.";
[email protected]9b600832011-10-26 20:31:59124
[email protected]6f371442011-11-09 06:45:46125 extensions::ProcessMap* process_map =
126 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52127
[email protected]3a8eecb2010-04-22 23:56:30128 host_resolver()->AddRule("*", "127.0.0.1");
[email protected]95409e12010-08-17 20:07:11129 ASSERT_TRUE(test_server()->Start());
[email protected]3a8eecb2010-04-22 23:56:30130
[email protected]cbf4d1912010-08-12 18:24:57131 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
[email protected]3a8eecb2010-04-22 23:56:30132
[email protected]87c7c292011-10-27 16:16:41133 LOG(INFO) << "Loaded extension.";
134
[email protected]cbf4d1912010-08-12 18:24:57135 // Open two tabs in the app, one outside it.
[email protected]118d3122011-08-10 17:09:53136 GURL base_url = GetTestBaseURL("app_process");
[email protected]fe3048872010-10-18 14:58:59137
[email protected]f0e13332011-05-20 22:41:14138 // Test both opening a URL in a new tab, and opening a tab and then navigating
139 // it. Either way, app tabs should be considered extension processes, but
140 // they have no elevated privileges and thus should not have WebUI bindings.
141 ui_test_utils::NavigateToURLWithDisposition(
142 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
143 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46144 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03145 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
146 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41147 LOG(INFO) << "Nav 1.";
148
149 ui_test_utils::NavigateToURLWithDisposition(
150 browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
151 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46152 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03153 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
154 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41155 LOG(INFO) << "Nav 2.";
156
157 ui_test_utils::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:42158 chrome::NOTIFICATION_TAB_ADDED,
[email protected]87c7c292011-10-27 16:16:41159 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:10160 chrome::NewTab(browser());
[email protected]87c7c292011-10-27 16:16:41161 tab_added_observer.Wait();
162 LOG(INFO) << "New tab.";
[email protected]cbf4d1912010-08-12 18:24:57163 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
[email protected]87c7c292011-10-27 16:16:41164 LOG(INFO) << "Nav 3.";
[email protected]6f371442011-11-09 06:45:46165 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03166 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost()->GetID()));
167 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 3)->GetWebUI());
[email protected]3a8eecb2010-04-22 23:56:30168
[email protected]056ad2a2011-07-12 02:13:55169 // We should have opened 3 new extension tabs. Including the original blank
170 // tab, we now have 4 tabs. Because the app_process app has the background
171 // permission, all of its instances are in the same process. Thus two tabs
172 // should be part of the extension app and grouped in the same process.
[email protected]3a8eecb2010-04-22 23:56:30173 ASSERT_EQ(4, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03174 WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
[email protected]cbf4d1912010-08-12 18:24:57175
[email protected]19da16a92012-05-23 17:11:29176 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03177 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]19da16a92012-05-23 17:11:29178 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03179 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:30180
181 // Now let's do the same using window.open. The same should happen.
[email protected]d8748142012-05-16 21:13:43182 ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29183 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41184 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]19da16a92012-05-23 17:11:29185 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41186 LOG(INFO) << "WindowOpenHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15187 // TODO(creis): This should open in a new process (i.e., false for the last
[email protected]ea7b7d82012-05-25 17:29:17188 // argument), but we temporarily avoid swapping processes away from a hosted
189 // app if it has an opener, because some OAuth providers make script calls
190 // between non-app popups and non-app iframes in the app process.
[email protected]361a5f1f2011-10-05 20:11:15191 // See crbug.com/59285.
[email protected]19da16a92012-05-23 17:11:29192 OpenWindow(tab, base_url.Resolve("path3/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41193 LOG(INFO) << "WindowOpenHelper 3.";
[email protected]3a8eecb2010-04-22 23:56:30194
195 // Now let's have these pages navigate, into or out of the extension web
196 // extent. They should switch processes.
[email protected]9a1e6d42010-04-26 22:29:36197 const GURL& app_url(base_url.Resolve("path1/empty.html"));
198 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03199 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
[email protected]87c7c292011-10-27 16:16:41200 LOG(INFO) << "NavigateTabHelper 1.";
[email protected]52877dbc62012-06-29 22:22:03201 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 3), app_url);
[email protected]87c7c292011-10-27 16:16:41202 LOG(INFO) << "NavigateTabHelper 2.";
[email protected]ea7b7d82012-05-25 17:29:17203 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03204 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]19da16a92012-05-23 17:11:29205 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03206 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04207
208 // If one of the popup tabs navigates back to the app, window.opener should
209 // be valid.
[email protected]52877dbc62012-06-29 22:22:03210 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 6), app_url);
[email protected]87c7c292011-10-27 16:16:41211 LOG(INFO) << "NavigateTabHelper 3.";
[email protected]19da16a92012-05-23 17:11:29212 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03213 chrome::GetWebContentsAt(browser(), 6)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04214 bool windowOpenerValid = false;
215 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]52877dbc62012-06-29 22:22:03216 chrome::GetWebContentsAt(browser(), 6)->GetRenderViewHost(), L"",
[email protected]08e94b82010-12-15 22:51:04217 L"window.domAutomationController.send(window.opener != null)",
218 &windowOpenerValid));
219 ASSERT_TRUE(windowOpenerValid);
[email protected]87c7c292011-10-27 16:16:41220
221 LOG(INFO) << "End of test.";
[email protected]3a8eecb2010-04-22 23:56:30222}
[email protected]faf407b2011-01-05 01:24:32223
[email protected]056ad2a2011-07-12 02:13:55224// Test that hosted apps without the background permission use a process per app
225// instance model, such that separate instances are in separate processes.
[email protected]19da16a92012-05-23 17:11:29226IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessInstances) {
[email protected]7b54ca02012-03-02 18:06:53227 TestAppInstancesHelper("app_process_instances");
228}
[email protected]87c7c292011-10-27 16:16:41229
[email protected]7b54ca02012-03-02 18:06:53230// Test that hosted apps with the background permission but that set
231// allow_js_access to false also use a process per app instance model.
232// Separate instances should be in separate processes.
[email protected]19da16a92012-05-23 17:11:29233IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessBackgroundInstances) {
[email protected]7b54ca02012-03-02 18:06:53234 TestAppInstancesHelper("app_process_background_instances");
[email protected]056ad2a2011-07-12 02:13:55235}
236
[email protected]15877ca2011-11-18 22:40:52237// Tests that bookmark apps do not use the app process model and are treated
238// like normal web pages instead. http://crbug.com/104636.
[email protected]19da16a92012-05-23 17:11:29239IN_PROC_BROWSER_TEST_F(AppApiTest, BookmarkAppGetsNormalProcess) {
[email protected]c2f36e3a2011-12-14 01:27:19240 ExtensionService* service = browser()->profile()->GetExtensionService();
241 extensions::ProcessMap* process_map = service->process_map();
[email protected]15877ca2011-11-18 22:40:52242
243 host_resolver()->AddRule("*", "127.0.0.1");
244 ASSERT_TRUE(test_server()->Start());
[email protected]15877ca2011-11-18 22:40:52245 GURL base_url = GetTestBaseURL("app_process");
246
[email protected]c2f36e3a2011-12-14 01:27:19247 // Load an app as a bookmark app.
248 std::string error;
249 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
250 test_data_dir_.AppendASCII("app_process"),
251 Extension::LOAD,
252 Extension::FROM_BOOKMARK,
253 &error));
[email protected]36a5c4c2011-12-14 16:34:50254 service->OnExtensionInstalled(extension, false,
255 StringOrdinal::CreateInitialOrdinal());
[email protected]c2f36e3a2011-12-14 01:27:19256 ASSERT_TRUE(extension.get());
257 ASSERT_TRUE(extension->from_bookmark());
258
[email protected]15877ca2011-11-18 22:40:52259 // Test both opening a URL in a new tab, and opening a tab and then navigating
260 // it. Either way, bookmark app tabs should be considered normal processes
261 // with no elevated privileges and no WebUI bindings.
262 ui_test_utils::NavigateToURLWithDisposition(
263 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
264 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
265 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03266 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
267 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52268
269 ui_test_utils::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:42270 chrome::NOTIFICATION_TAB_ADDED,
[email protected]15877ca2011-11-18 22:40:52271 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:10272 chrome::NewTab(browser());
[email protected]15877ca2011-11-18 22:40:52273 tab_added_observer.Wait();
274 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
275 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03276 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
277 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52278
279 // We should have opened 2 new bookmark app tabs. Including the original blank
280 // tab, we now have 3 tabs. Because normal pages use the
281 // process-per-site-instance model, each should be in its own process.
282 ASSERT_EQ(3, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03283 WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
[email protected]19da16a92012-05-23 17:11:29284 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03285 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52286
287 // Now let's do the same using window.open. The same should happen.
[email protected]d8748142012-05-16 21:13:43288 ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29289 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
290 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]15877ca2011-11-18 22:40:52291
292 // Now let's have a tab navigate out of and back into the app's web
293 // extent. Neither navigation should switch processes.
294 const GURL& app_url(base_url.Resolve("path1/empty.html"));
295 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03296 RenderViewHost* host2 =
297 chrome::GetWebContentsAt(browser(), 2)->GetRenderViewHost();
298 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
[email protected]9f76c1e2012-03-05 15:15:58299 EXPECT_EQ(host2->GetProcess(),
[email protected]52877dbc62012-06-29 22:22:03300 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
301 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), app_url);
[email protected]9f76c1e2012-03-05 15:15:58302 EXPECT_EQ(host2->GetProcess(),
[email protected]52877dbc62012-06-29 22:22:03303 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52304}
305
[email protected]faf407b2011-01-05 01:24:32306// Tests that app process switching works properly in the following scenario:
307// 1. navigate to a page1 in the app
308// 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
309// 3. page2 redirects back to a page in the app
310// The final navigation should end up in the app process.
311// See http://crbug.com/61757
[email protected]ea7b7d82012-05-25 17:29:17312IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
[email protected]faf407b2011-01-05 01:24:32313 host_resolver()->AddRule("*", "127.0.0.1");
314 ASSERT_TRUE(test_server()->Start());
315
316 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
317
318 // Open two tabs in the app.
[email protected]118d3122011-08-10 17:09:53319 GURL base_url = GetTestBaseURL("app_process");
[email protected]faf407b2011-01-05 01:24:32320
[email protected]a37d4b02012-06-25 21:56:10321 chrome::NewTab(browser());
[email protected]faf407b2011-01-05 01:24:32322 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]a37d4b02012-06-25 21:56:10323 chrome::NewTab(browser());
[email protected]ea7b7d82012-05-25 17:29:17324 // Wait until the second tab finishes its redirect train (2 hops).
[email protected]4ad5d77d2011-12-03 02:00:48325 // 1. We navigate to redirect.html
326 // 2. Renderer navigates and finishes, counting as a load stop.
327 // 3. Renderer issues the meta refresh to navigate to server-redirect.
328 // 4. Renderer is now in a "provisional load", waiting for navigation to
329 // complete.
330 // 5. Browser sees a redirect response from server-redirect to empty.html, and
331 // transfers that to a new navigation, using RequestTransferURL.
[email protected]ea7b7d82012-05-25 17:29:17332 // 6. Renderer navigates to empty.html, and finishes loading, counting as the
333 // second load stop
[email protected]4ad5d77d2011-12-03 02:00:48334 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
[email protected]ea7b7d82012-05-25 17:29:17335 browser(), base_url.Resolve("path1/redirect.html"), 2);
[email protected]faf407b2011-01-05 01:24:32336
337 // 3 tabs, including the initial about:blank. The last 2 should be the same
338 // process.
339 ASSERT_EQ(3, browser()->tab_count());
[email protected]089e8c332011-01-06 21:37:29340 EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
[email protected]52877dbc62012-06-29 22:22:03341 chrome::GetWebContentsAt(browser(), 2)->GetController().
[email protected]36fc0392011-12-25 03:59:51342 GetLastCommittedEntry()->GetURL().path());
[email protected]52877dbc62012-06-29 22:22:03343 EXPECT_EQ(chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost(),
344 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]faf407b2011-01-05 01:24:32345}
[email protected]d292d8a2011-05-25 03:47:11346
347// Ensure that reloading a URL after installing or uninstalling it as an app
348// correctly swaps the process. (http://crbug.com/80621)
[email protected]28505fc2012-05-02 10:33:09349//
350// The test times out under AddressSanitizer, see http://crbug.com/103371
351#if defined(ADDRESS_SANITIZER)
352#define MAYBE_ReloadIntoAppProcess DISABLED_ReloadIntoAppProcess
353#else
354#define MAYBE_ReloadIntoAppProcess ReloadIntoAppProcess
355#endif
356IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadIntoAppProcess) {
[email protected]6f371442011-11-09 06:45:46357 extensions::ProcessMap* process_map =
358 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52359
[email protected]d292d8a2011-05-25 03:47:11360 host_resolver()->AddRule("*", "127.0.0.1");
361 ASSERT_TRUE(test_server()->Start());
362
363 // The app under test acts on URLs whose host is "localhost",
364 // so the URLs we navigate to must have host "localhost".
[email protected]118d3122011-08-10 17:09:53365 GURL base_url = GetTestBaseURL("app_process");
[email protected]d292d8a2011-05-25 03:47:11366
367 // Load an app URL before loading the app.
368 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03369 WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
[email protected]6f371442011-11-09 06:45:46370 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52371 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11372
[email protected]8d3132f62011-10-12 07:13:42373 // Load app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11374 const Extension* app =
375 LoadExtension(test_data_dir_.AppendASCII("app_process"));
376 ASSERT_TRUE(app);
377 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46378 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52379 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11380
[email protected]8d3132f62011-10-12 07:13:42381 // Disable app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11382 DisableExtension(app->id());
383 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46384 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52385 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11386
[email protected]8d3132f62011-10-12 07:13:42387 // Enable app and reload the page.
388 EnableExtension(app->id());
389 ui_test_utils::WindowedNotificationObserver reload_observer(
390 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50391 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03392 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10393 chrome::Reload(browser(), CURRENT_TAB);
[email protected]8d3132f62011-10-12 07:13:42394 reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46395 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52396 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42397
398 // Disable app and reload the page.
399 DisableExtension(app->id());
400 ui_test_utils::WindowedNotificationObserver reload_observer2(
401 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50402 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03403 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10404 chrome::Reload(browser(), CURRENT_TAB);
[email protected]8d3132f62011-10-12 07:13:42405 reload_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46406 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52407 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42408
[email protected]d292d8a2011-05-25 03:47:11409 // Enable app and reload via JavaScript.
410 EnableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42411 ui_test_utils::WindowedNotificationObserver js_reload_observer(
412 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50413 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03414 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]151a63d2011-12-20 22:32:52415 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]d292d8a2011-05-25 03:47:11416 L"", L"location.reload();"));
[email protected]8d3132f62011-10-12 07:13:42417 js_reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46418 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52419 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11420
421 // Disable app and reload via JavaScript.
422 DisableExtension(app->id());
[email protected]8d3132f62011-10-12 07:13:42423 ui_test_utils::WindowedNotificationObserver js_reload_observer2(
424 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50425 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03426 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]151a63d2011-12-20 22:32:52427 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(contents->GetRenderViewHost(),
[email protected]bcd904482012-02-01 01:54:22428 L"", L"location = location;"));
[email protected]8d3132f62011-10-12 07:13:42429 js_reload_observer2.Wait();
[email protected]6f371442011-11-09 06:45:46430 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52431 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11432}
[email protected]118d3122011-08-10 17:09:53433
[email protected]118d3122011-08-10 17:09:53434// Tests that if we have a non-app process (path3/container.html) that has an
435// iframe with a URL in the app's extent (path1/iframe.html), then opening a
436// link from that iframe to a new window to a URL in the app's extent (path1/
437// empty.html) results in the new window being in an app process. See
438// http://crbug.com/89272 for more details.
[email protected]19da16a92012-05-23 17:11:29439IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
[email protected]6f371442011-11-09 06:45:46440 extensions::ProcessMap* process_map =
441 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52442
[email protected]118d3122011-08-10 17:09:53443 host_resolver()->AddRule("*", "127.0.0.1");
444 ASSERT_TRUE(test_server()->Start());
445
446 GURL base_url = GetTestBaseURL("app_process");
447
448 // Load app and start URL (not in the app).
449 const Extension* app =
450 LoadExtension(test_data_dir_.AppendASCII("app_process"));
451 ASSERT_TRUE(app);
[email protected]19da16a92012-05-23 17:11:29452
453 ui_test_utils::WindowedNotificationObserver popup_observer(
454 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
455 content::NotificationService::AllSources());
456 ui_test_utils::NavigateToURL(browser(),
457 base_url.Resolve("path3/container.html"));
[email protected]6f371442011-11-09 06:45:46458 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03459 chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost()->GetID()));
[email protected]19da16a92012-05-23 17:11:29460 popup_observer.Wait();
[email protected]118d3122011-08-10 17:09:53461
462 // Popup window should be in the app's process.
[email protected]19da16a92012-05-23 17:11:29463 RenderViewHost* popup_host =
464 content::Source<RenderViewHost>(popup_observer.source()).ptr();
465 EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
[email protected]118d3122011-08-10 17:09:53466}
[email protected]a09add52011-08-12 03:59:23467
[email protected]88aae972011-12-16 01:14:18468// Tests that if an extension launches an app via chrome.tabs.create with an URL
469// that's not in the app's extent but that redirects to it, we still end up with
470// an app process. See http://crbug.com/99349 for more details.
471IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromExtension) {
472 host_resolver()->AddRule("*", "127.0.0.1");
473 ASSERT_TRUE(StartTestServer());
474
475 LoadExtension(test_data_dir_.AppendASCII("app_process"));
476 const Extension* launcher =
477 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
478
479 // There should be three navigations by the time the app page is loaded.
480 // 1. The extension launcher page.
481 // 2. The URL that the extension launches, which redirects.
482 // 3. The app's URL.
[email protected]5b8ff1c2012-06-02 20:42:20483 content::TestNavigationObserver test_navigation_observer(
484 content::NotificationService::AllSources(),
485 NULL,
486 3);
[email protected]88aae972011-12-16 01:14:18487
488 // Load the launcher extension, which should launch the app.
489 ui_test_utils::NavigateToURLWithDisposition(
490 browser(),
491 launcher->GetResourceURL("main.html"),
492 CURRENT_TAB,
493 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
494
495 // Wait for app tab to be created and loaded.
496 test_navigation_observer.WaitForObservation(
497 base::Bind(&ui_test_utils::RunMessageLoop),
498 base::Bind(&MessageLoop::Quit,
499 base::Unretained(MessageLoopForUI::current())));
500
501 // App has loaded, and chrome.app.isInstalled should be true.
502 bool is_installed = false;
503 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]52877dbc62012-06-29 22:22:03504 chrome::GetActiveWebContents(browser())->GetRenderViewHost(), L"",
[email protected]88aae972011-12-16 01:14:18505 L"window.domAutomationController.send(chrome.app.isInstalled)",
506 &is_installed));
507 ASSERT_TRUE(is_installed);
508}
509
[email protected]d55c2382011-08-18 23:10:36510// Tests that if we have an app process (path1/container.html) with a non-app
511// iframe (path3/iframe.html), then opening a link from that iframe to a new
512// window to a same-origin non-app URL (path3/empty.html) should keep the window
513// in the app process.
514// This is in contrast to OpenAppFromIframe, since here the popup will not be
515// missing special permissions and should be scriptable from the iframe.
516// See http://crbug.com/92669 for more details.
[email protected]19da16a92012-05-23 17:11:29517IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
[email protected]6f371442011-11-09 06:45:46518 extensions::ProcessMap* process_map =
519 browser()->profile()->GetExtensionService()->process_map();
[email protected]718eab62011-10-05 21:16:52520
[email protected]d55c2382011-08-18 23:10:36521 host_resolver()->AddRule("*", "127.0.0.1");
522 ASSERT_TRUE(test_server()->Start());
523
524 GURL base_url = GetTestBaseURL("app_process");
525
526 // Load app and start URL (in the app).
527 const Extension* app =
528 LoadExtension(test_data_dir_.AppendASCII("app_process"));
529 ASSERT_TRUE(app);
[email protected]19da16a92012-05-23 17:11:29530
531 ui_test_utils::WindowedNotificationObserver popup_observer(
532 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
533 content::NotificationService::AllSources());
534 ui_test_utils::NavigateToURL(browser(),
535 base_url.Resolve("path1/container.html"));
[email protected]f3b1a082011-11-18 00:34:30536 content::RenderProcessHost* process =
[email protected]52877dbc62012-06-29 22:22:03537 chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost();
[email protected]f3b1a082011-11-18 00:34:30538 EXPECT_TRUE(process_map->Contains(process->GetID()));
[email protected]d55c2382011-08-18 23:10:36539
[email protected]19da16a92012-05-23 17:11:29540 // Wait for popup window to appear.
541 popup_observer.Wait();
[email protected]d55c2382011-08-18 23:10:36542
543 // Popup window should be in the app's process.
[email protected]19da16a92012-05-23 17:11:29544 RenderViewHost* popup_host =
545 content::Source<RenderViewHost>(popup_observer.source()).ptr();
546 EXPECT_EQ(process, popup_host->GetProcess());
[email protected]d55c2382011-08-18 23:10:36547}
548
[email protected]a344b762012-03-16 18:53:49549// http://crbug.com/118502
550#if defined(OS_MACOSX) || defined(OS_LINUX)
551#define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
552#else
553#define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
554#endif
555IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
[email protected]6f371442011-11-09 06:45:46556 extensions::ProcessMap* process_map =
557 browser()->profile()->GetExtensionService()->process_map();
558
[email protected]a09add52011-08-12 03:59:23559 host_resolver()->AddRule("*", "127.0.0.1");
560 ASSERT_TRUE(test_server()->Start());
561
562 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
563
564 GURL base_url = GetTestBaseURL("app_process");
565
566 // Load the app, chrome.app.isInstalled should be true.
567 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03568 WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
[email protected]6f371442011-11-09 06:45:46569 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52570 contents->GetRenderProcessHost()->GetID()));
[email protected]a09add52011-08-12 03:59:23571 bool is_installed = false;
572 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52573 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23574 L"window.domAutomationController.send(chrome.app.isInstalled)",
575 &is_installed));
576 ASSERT_TRUE(is_installed);
577
578 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
[email protected]52877dbc62012-06-29 22:22:03579 ui_test_utils::CrashTab(chrome::GetActiveWebContents(browser()));
[email protected]ae673742011-08-24 19:48:37580 ui_test_utils::WindowedNotificationObserver observer(
581 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50582 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03583 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10584 chrome::Reload(browser(), CURRENT_TAB);
[email protected]ae673742011-08-24 19:48:37585 observer.Wait();
[email protected]a09add52011-08-12 03:59:23586 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52587 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23588 L"window.domAutomationController.send(chrome.app.isInstalled)",
589 &is_installed));
590 ASSERT_TRUE(is_installed);
591}