blob: d6a68aaae67b9a4ad7b9386defd93291015382c8 [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"
[email protected]06bdd2b2012-11-30 18:47:138#include "chrome/browser/extensions/extension_system.h"
[email protected]6f371442011-11-09 06:45:469#include "chrome/browser/extensions/process_map.h"
[email protected]8ecad5e2010-12-02 21:18:3310#include "chrome/browser/profiles/profile.h"
[email protected]079b3cc2012-09-26 19:59:1311#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
[email protected]7b5dc002010-11-16 23:08:1012#include "chrome/browser/ui/browser.h"
[email protected]a37d4b02012-06-25 21:56:1013#include "chrome/browser/ui/browser_commands.h"
[email protected]d8748142012-05-16 21:13:4314#include "chrome/browser/ui/browser_finder.h"
[email protected]71b73f02011-04-06 15:57:2915#include "chrome/browser/ui/browser_list.h"
[email protected]52877dbc62012-06-29 22:22:0316#include "chrome/browser/ui/browser_tabstrip.h"
[email protected]d55c2382011-08-18 23:10:3617#include "chrome/browser/ui/browser_window.h"
[email protected]b62084b2012-06-12 01:53:3018#include "chrome/browser/ui/tab_contents/tab_contents.h"
[email protected]884033e2012-04-16 19:38:4219#include "chrome/common/chrome_notification_types.h"
[email protected]3a8eecb2010-04-22 23:56:3020#include "chrome/common/chrome_switches.h"
[email protected]814a7bf0f2011-08-13 05:30:5921#include "chrome/common/extensions/extension.h"
[email protected]c2f36e3a2011-12-14 01:27:1922#include "chrome/common/extensions/extension_file_util.h"
[email protected]af44e7fb2011-07-29 18:32:3223#include "chrome/test/base/ui_test_utils.h"
[email protected]ad23a092011-12-28 07:02:0424#include "content/public/browser/navigation_entry.h"
[email protected]ad50def52011-10-19 23:17:0725#include "content/public/browser/notification_service.h"
[email protected]c333e792012-01-06 16:57:3926#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3327#include "content/public/browser/render_view_host.h"
[email protected]6acde6352012-01-04 16:52:2028#include "content/public/browser/web_contents.h"
[email protected]7d478cb2012-07-24 17:19:4229#include "content/public/test/browser_test_utils.h"
[email protected]5b8ff1c2012-06-02 20:42:2030#include "content/public/test/test_navigation_observer.h"
[email protected]3a8eecb2010-04-22 23:56:3031#include "net/base/mock_host_resolver.h"
[email protected]36b643212012-09-07 12:53:0032#include "sync/api/string_ordinal.h"
[email protected]3a8eecb2010-04-22 23:56:3033
[email protected]c5eed492012-01-04 17:07:5034using content::NavigationController;
[email protected]eaabba22012-03-07 15:02:1135using content::RenderViewHost;
[email protected]4ca15302012-01-03 05:53:2036using content::WebContents;
[email protected]1c321ee52012-05-21 03:02:3437using extensions::Extension;
[email protected]4ca15302012-01-03 05:53:2038
[email protected]7b54ca02012-03-02 18:06:5339class AppApiTest : public ExtensionApiTest {
40 protected:
41 // Gets the base URL for files for a specific test, making sure that it uses
42 // "localhost" as the hostname, since that is what the extent is declared
43 // as in the test apps manifests.
44 GURL GetTestBaseURL(std::string test_directory) {
45 GURL::Replacements replace_host;
46 std::string host_str("localhost"); // must stay in scope with replace_host
47 replace_host.SetHostStr(host_str);
48 GURL base_url = test_server()->GetURL(
49 "files/extensions/api_test/" + test_directory + "/");
50 return base_url.ReplaceComponents(replace_host);
51 }
52
53 // Pass flags to make testing apps easier.
54 void SetUpCommandLine(CommandLine* command_line) {
55 ExtensionApiTest::SetUpCommandLine(command_line);
56 CommandLine::ForCurrentProcess()->AppendSwitch(
57 switches::kDisablePopupBlocking);
58 CommandLine::ForCurrentProcess()->AppendSwitch(
59 switches::kAllowHTTPBackgroundPage);
60 }
61
62 // Helper function to test that independent tabs of the named app are loaded
63 // into separate processes.
64 void TestAppInstancesHelper(std::string app_name) {
65 LOG(INFO) << "Start of test.";
66
[email protected]06bdd2b2012-11-30 18:47:1367 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
68 browser()->profile())->extension_service()->process_map();
[email protected]7b54ca02012-03-02 18:06:5369
70 host_resolver()->AddRule("*", "127.0.0.1");
71 ASSERT_TRUE(test_server()->Start());
72
73 ASSERT_TRUE(LoadExtension(
74 test_data_dir_.AppendASCII(app_name)));
75
76 // Open two tabs in the app, one outside it.
77 GURL base_url = GetTestBaseURL(app_name);
78
79 // Test both opening a URL in a new tab, and opening a tab and then
80 // navigating it. Either way, app tabs should be considered extension
81 // processes, but they have no elevated privileges and thus should not
82 // have WebUI bindings.
83 ui_test_utils::NavigateToURLWithDisposition(
84 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
85 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
86 LOG(INFO) << "Nav 1.";
87 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:0388 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
89 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]7b54ca02012-03-02 18:06:5390
[email protected]a7fe9112012-07-20 02:34:4591 content::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:4292 chrome::NOTIFICATION_TAB_ADDED,
[email protected]7b54ca02012-03-02 18:06:5393 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:1094 chrome::NewTab(browser());
[email protected]7b54ca02012-03-02 18:06:5395 tab_added_observer.Wait();
96 LOG(INFO) << "New tab.";
97 ui_test_utils::NavigateToURL(browser(),
98 base_url.Resolve("path2/empty.html"));
99 LOG(INFO) << "Nav 2.";
100 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03101 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
102 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]7b54ca02012-03-02 18:06:53103
104 // We should have opened 2 new extension tabs. Including the original blank
105 // tab, we now have 3 tabs. The two app tabs should not be in the same
106 // process, since they do not have the background permission. (Thus, we
107 // want to separate them to improve responsiveness.)
108 ASSERT_EQ(3, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03109 WebContents* tab1 = chrome::GetWebContentsAt(browser(), 1);
110 WebContents* tab2 = chrome::GetWebContentsAt(browser(), 2);
[email protected]19da16a92012-05-23 17:11:29111 EXPECT_NE(tab1->GetRenderProcessHost(), tab2->GetRenderProcessHost());
[email protected]7b54ca02012-03-02 18:06:53112
113 // Opening tabs with window.open should keep the page in the opener's
114 // process.
[email protected]52ff7d932012-10-28 19:46:46115 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29116 OpenWindow(tab1, base_url.Resolve("path1/empty.html"), true, NULL);
[email protected]7b54ca02012-03-02 18:06:53117 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]19da16a92012-05-23 17:11:29118 OpenWindow(tab2, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]7b54ca02012-03-02 18:06:53119 LOG(INFO) << "End of test.";
120 }
121};
122
[email protected]079b3cc2012-09-26 19:59:13123// Omits the disable-popup-blocking flag so we can cover that case.
124class BlockedAppApiTest : public AppApiTest {
125 protected:
126 void SetUpCommandLine(CommandLine* command_line) {
127 ExtensionApiTest::SetUpCommandLine(command_line);
128 CommandLine::ForCurrentProcess()->AppendSwitch(
129 switches::kAllowHTTPBackgroundPage);
130 }
131};
132
[email protected]7b54ca02012-03-02 18:06:53133// Tests that hosted apps with the background permission get a process-per-app
134// model, since all pages need to be able to script the background page.
[email protected]19da16a92012-05-23 17:11:29135IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
[email protected]87c7c292011-10-27 16:16:41136 LOG(INFO) << "Start of test.";
[email protected]9b600832011-10-26 20:31:59137
[email protected]06bdd2b2012-11-30 18:47:13138 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
139 browser()->profile())->extension_service()->process_map();
[email protected]718eab62011-10-05 21:16:52140
[email protected]3a8eecb2010-04-22 23:56:30141 host_resolver()->AddRule("*", "127.0.0.1");
[email protected]95409e12010-08-17 20:07:11142 ASSERT_TRUE(test_server()->Start());
[email protected]3a8eecb2010-04-22 23:56:30143
[email protected]cbf4d1912010-08-12 18:24:57144 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
[email protected]3a8eecb2010-04-22 23:56:30145
[email protected]87c7c292011-10-27 16:16:41146 LOG(INFO) << "Loaded extension.";
147
[email protected]cbf4d1912010-08-12 18:24:57148 // Open two tabs in the app, one outside it.
[email protected]118d3122011-08-10 17:09:53149 GURL base_url = GetTestBaseURL("app_process");
[email protected]fe3048872010-10-18 14:58:59150
[email protected]f0e13332011-05-20 22:41:14151 // Test both opening a URL in a new tab, and opening a tab and then navigating
152 // it. Either way, app tabs should be considered extension processes, but
153 // they have no elevated privileges and thus should not have WebUI bindings.
154 ui_test_utils::NavigateToURLWithDisposition(
155 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
156 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46157 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03158 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
159 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41160 LOG(INFO) << "Nav 1.";
161
162 ui_test_utils::NavigateToURLWithDisposition(
163 browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
164 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
[email protected]6f371442011-11-09 06:45:46165 EXPECT_TRUE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03166 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
167 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]87c7c292011-10-27 16:16:41168 LOG(INFO) << "Nav 2.";
169
[email protected]a7fe9112012-07-20 02:34:45170 content::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:42171 chrome::NOTIFICATION_TAB_ADDED,
[email protected]87c7c292011-10-27 16:16:41172 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:10173 chrome::NewTab(browser());
[email protected]87c7c292011-10-27 16:16:41174 tab_added_observer.Wait();
175 LOG(INFO) << "New tab.";
[email protected]cbf4d1912010-08-12 18:24:57176 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
[email protected]87c7c292011-10-27 16:16:41177 LOG(INFO) << "Nav 3.";
[email protected]6f371442011-11-09 06:45:46178 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03179 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost()->GetID()));
180 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 3)->GetWebUI());
[email protected]3a8eecb2010-04-22 23:56:30181
[email protected]056ad2a2011-07-12 02:13:55182 // We should have opened 3 new extension tabs. Including the original blank
183 // tab, we now have 4 tabs. Because the app_process app has the background
184 // permission, all of its instances are in the same process. Thus two tabs
185 // should be part of the extension app and grouped in the same process.
[email protected]3a8eecb2010-04-22 23:56:30186 ASSERT_EQ(4, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03187 WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
[email protected]cbf4d1912010-08-12 18:24:57188
[email protected]19da16a92012-05-23 17:11:29189 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03190 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]19da16a92012-05-23 17:11:29191 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03192 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
[email protected]3a8eecb2010-04-22 23:56:30193
194 // Now let's do the same using window.open. The same should happen.
[email protected]52ff7d932012-10-28 19:46:46195 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29196 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41197 LOG(INFO) << "WindowOpenHelper 1.";
[email protected]19da16a92012-05-23 17:11:29198 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41199 LOG(INFO) << "WindowOpenHelper 2.";
[email protected]361a5f1f2011-10-05 20:11:15200 // TODO(creis): This should open in a new process (i.e., false for the last
[email protected]ea7b7d82012-05-25 17:29:17201 // argument), but we temporarily avoid swapping processes away from a hosted
202 // app if it has an opener, because some OAuth providers make script calls
203 // between non-app popups and non-app iframes in the app process.
[email protected]361a5f1f2011-10-05 20:11:15204 // See crbug.com/59285.
[email protected]19da16a92012-05-23 17:11:29205 OpenWindow(tab, base_url.Resolve("path3/empty.html"), true, NULL);
[email protected]87c7c292011-10-27 16:16:41206 LOG(INFO) << "WindowOpenHelper 3.";
[email protected]3a8eecb2010-04-22 23:56:30207
208 // Now let's have these pages navigate, into or out of the extension web
209 // extent. They should switch processes.
[email protected]9a1e6d42010-04-26 22:29:36210 const GURL& app_url(base_url.Resolve("path1/empty.html"));
211 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03212 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
[email protected]87c7c292011-10-27 16:16:41213 LOG(INFO) << "NavigateTabHelper 1.";
[email protected]52877dbc62012-06-29 22:22:03214 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 3), app_url);
[email protected]87c7c292011-10-27 16:16:41215 LOG(INFO) << "NavigateTabHelper 2.";
[email protected]ea7b7d82012-05-25 17:29:17216 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03217 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]19da16a92012-05-23 17:11:29218 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03219 chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04220
221 // If one of the popup tabs navigates back to the app, window.opener should
222 // be valid.
[email protected]52877dbc62012-06-29 22:22:03223 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 6), app_url);
[email protected]87c7c292011-10-27 16:16:41224 LOG(INFO) << "NavigateTabHelper 3.";
[email protected]19da16a92012-05-23 17:11:29225 EXPECT_EQ(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03226 chrome::GetWebContentsAt(browser(), 6)->GetRenderProcessHost());
[email protected]08e94b82010-12-15 22:51:04227 bool windowOpenerValid = false;
[email protected]7d478cb2012-07-24 17:19:42228 ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
[email protected]52877dbc62012-06-29 22:22:03229 chrome::GetWebContentsAt(browser(), 6)->GetRenderViewHost(), L"",
[email protected]08e94b82010-12-15 22:51:04230 L"window.domAutomationController.send(window.opener != null)",
231 &windowOpenerValid));
232 ASSERT_TRUE(windowOpenerValid);
[email protected]87c7c292011-10-27 16:16:41233
234 LOG(INFO) << "End of test.";
[email protected]3a8eecb2010-04-22 23:56:30235}
[email protected]faf407b2011-01-05 01:24:32236
[email protected]056ad2a2011-07-12 02:13:55237// Test that hosted apps without the background permission use a process per app
238// instance model, such that separate instances are in separate processes.
[email protected]19da16a92012-05-23 17:11:29239IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessInstances) {
[email protected]7b54ca02012-03-02 18:06:53240 TestAppInstancesHelper("app_process_instances");
241}
[email protected]87c7c292011-10-27 16:16:41242
[email protected]7b54ca02012-03-02 18:06:53243// Test that hosted apps with the background permission but that set
244// allow_js_access to false also use a process per app instance model.
245// Separate instances should be in separate processes.
[email protected]19da16a92012-05-23 17:11:29246IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessBackgroundInstances) {
[email protected]7b54ca02012-03-02 18:06:53247 TestAppInstancesHelper("app_process_background_instances");
[email protected]056ad2a2011-07-12 02:13:55248}
249
[email protected]15877ca2011-11-18 22:40:52250// Tests that bookmark apps do not use the app process model and are treated
251// like normal web pages instead. http://crbug.com/104636.
[email protected]19da16a92012-05-23 17:11:29252IN_PROC_BROWSER_TEST_F(AppApiTest, BookmarkAppGetsNormalProcess) {
[email protected]06bdd2b2012-11-30 18:47:13253 ExtensionService* service = extensions::ExtensionSystem::Get(
254 browser()->profile())->extension_service();
[email protected]c2f36e3a2011-12-14 01:27:19255 extensions::ProcessMap* process_map = service->process_map();
[email protected]15877ca2011-11-18 22:40:52256
257 host_resolver()->AddRule("*", "127.0.0.1");
258 ASSERT_TRUE(test_server()->Start());
[email protected]15877ca2011-11-18 22:40:52259 GURL base_url = GetTestBaseURL("app_process");
260
[email protected]c2f36e3a2011-12-14 01:27:19261 // Load an app as a bookmark app.
262 std::string error;
263 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
264 test_data_dir_.AppendASCII("app_process"),
265 Extension::LOAD,
266 Extension::FROM_BOOKMARK,
267 &error));
[email protected]26367b62012-10-04 23:03:32268 service->OnExtensionInstalled(extension,
[email protected]98270432012-09-11 20:51:24269 syncer::StringOrdinal::CreateInitialOrdinal(),
[email protected]0db124b02012-11-07 04:55:05270 false /* no requirement errors */,
271 false /* don't wait for idle */);
[email protected]c2f36e3a2011-12-14 01:27:19272 ASSERT_TRUE(extension.get());
273 ASSERT_TRUE(extension->from_bookmark());
274
[email protected]15877ca2011-11-18 22:40:52275 // Test both opening a URL in a new tab, and opening a tab and then navigating
276 // it. Either way, bookmark app tabs should be considered normal processes
277 // with no elevated privileges and no WebUI bindings.
278 ui_test_utils::NavigateToURLWithDisposition(
279 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
280 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
281 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03282 chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
283 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52284
[email protected]a7fe9112012-07-20 02:34:45285 content::WindowedNotificationObserver tab_added_observer(
[email protected]884033e2012-04-16 19:38:42286 chrome::NOTIFICATION_TAB_ADDED,
[email protected]15877ca2011-11-18 22:40:52287 content::NotificationService::AllSources());
[email protected]a37d4b02012-06-25 21:56:10288 chrome::NewTab(browser());
[email protected]15877ca2011-11-18 22:40:52289 tab_added_observer.Wait();
290 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
291 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03292 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
293 EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
[email protected]15877ca2011-11-18 22:40:52294
295 // We should have opened 2 new bookmark app tabs. Including the original blank
296 // tab, we now have 3 tabs. Because normal pages use the
297 // process-per-site-instance model, each should be in its own process.
298 ASSERT_EQ(3, browser()->tab_count());
[email protected]52877dbc62012-06-29 22:22:03299 WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
[email protected]19da16a92012-05-23 17:11:29300 EXPECT_NE(tab->GetRenderProcessHost(),
[email protected]52877dbc62012-06-29 22:22:03301 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52302
303 // Now let's do the same using window.open. The same should happen.
[email protected]52ff7d932012-10-28 19:46:46304 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
[email protected]19da16a92012-05-23 17:11:29305 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
306 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
[email protected]15877ca2011-11-18 22:40:52307
308 // Now let's have a tab navigate out of and back into the app's web
309 // extent. Neither navigation should switch processes.
310 const GURL& app_url(base_url.Resolve("path1/empty.html"));
311 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03312 RenderViewHost* host2 =
313 chrome::GetWebContentsAt(browser(), 2)->GetRenderViewHost();
314 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
[email protected]9f76c1e2012-03-05 15:15:58315 EXPECT_EQ(host2->GetProcess(),
[email protected]52877dbc62012-06-29 22:22:03316 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
317 NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), app_url);
[email protected]9f76c1e2012-03-05 15:15:58318 EXPECT_EQ(host2->GetProcess(),
[email protected]52877dbc62012-06-29 22:22:03319 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]15877ca2011-11-18 22:40:52320}
321
[email protected]faf407b2011-01-05 01:24:32322// Tests that app process switching works properly in the following scenario:
323// 1. navigate to a page1 in the app
324// 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
325// 3. page2 redirects back to a page in the app
326// The final navigation should end up in the app process.
327// See http://crbug.com/61757
[email protected]ea7b7d82012-05-25 17:29:17328IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
[email protected]faf407b2011-01-05 01:24:32329 host_resolver()->AddRule("*", "127.0.0.1");
330 ASSERT_TRUE(test_server()->Start());
331
332 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
333
334 // Open two tabs in the app.
[email protected]118d3122011-08-10 17:09:53335 GURL base_url = GetTestBaseURL("app_process");
[email protected]faf407b2011-01-05 01:24:32336
[email protected]a37d4b02012-06-25 21:56:10337 chrome::NewTab(browser());
[email protected]faf407b2011-01-05 01:24:32338 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]a37d4b02012-06-25 21:56:10339 chrome::NewTab(browser());
[email protected]ea7b7d82012-05-25 17:29:17340 // Wait until the second tab finishes its redirect train (2 hops).
[email protected]4ad5d77d2011-12-03 02:00:48341 // 1. We navigate to redirect.html
342 // 2. Renderer navigates and finishes, counting as a load stop.
343 // 3. Renderer issues the meta refresh to navigate to server-redirect.
344 // 4. Renderer is now in a "provisional load", waiting for navigation to
345 // complete.
346 // 5. Browser sees a redirect response from server-redirect to empty.html, and
347 // transfers that to a new navigation, using RequestTransferURL.
[email protected]ea7b7d82012-05-25 17:29:17348 // 6. Renderer navigates to empty.html, and finishes loading, counting as the
349 // second load stop
[email protected]4ad5d77d2011-12-03 02:00:48350 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
[email protected]ea7b7d82012-05-25 17:29:17351 browser(), base_url.Resolve("path1/redirect.html"), 2);
[email protected]faf407b2011-01-05 01:24:32352
353 // 3 tabs, including the initial about:blank. The last 2 should be the same
354 // process.
355 ASSERT_EQ(3, browser()->tab_count());
[email protected]089e8c332011-01-06 21:37:29356 EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
[email protected]52877dbc62012-06-29 22:22:03357 chrome::GetWebContentsAt(browser(), 2)->GetController().
[email protected]36fc0392011-12-25 03:59:51358 GetLastCommittedEntry()->GetURL().path());
[email protected]52877dbc62012-06-29 22:22:03359 EXPECT_EQ(chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost(),
360 chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
[email protected]faf407b2011-01-05 01:24:32361}
[email protected]d292d8a2011-05-25 03:47:11362
363// Ensure that reloading a URL after installing or uninstalling it as an app
364// correctly swaps the process. (http://crbug.com/80621)
[email protected]28505fc2012-05-02 10:33:09365//
366// The test times out under AddressSanitizer, see http://crbug.com/103371
367#if defined(ADDRESS_SANITIZER)
368#define MAYBE_ReloadIntoAppProcess DISABLED_ReloadIntoAppProcess
369#else
370#define MAYBE_ReloadIntoAppProcess ReloadIntoAppProcess
371#endif
372IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadIntoAppProcess) {
[email protected]06bdd2b2012-11-30 18:47:13373 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
374 browser()->profile())->extension_service()->process_map();
[email protected]718eab62011-10-05 21:16:52375
[email protected]d292d8a2011-05-25 03:47:11376 host_resolver()->AddRule("*", "127.0.0.1");
377 ASSERT_TRUE(test_server()->Start());
378
379 // The app under test acts on URLs whose host is "localhost",
380 // so the URLs we navigate to must have host "localhost".
[email protected]118d3122011-08-10 17:09:53381 GURL base_url = GetTestBaseURL("app_process");
[email protected]d292d8a2011-05-25 03:47:11382
383 // Load an app URL before loading the app.
384 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03385 WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
[email protected]6f371442011-11-09 06:45:46386 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52387 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11388
[email protected]8d3132f62011-10-12 07:13:42389 // Load app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11390 const Extension* app =
391 LoadExtension(test_data_dir_.AppendASCII("app_process"));
392 ASSERT_TRUE(app);
393 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46394 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52395 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11396
[email protected]8d3132f62011-10-12 07:13:42397 // Disable app and navigate to the page.
[email protected]d292d8a2011-05-25 03:47:11398 DisableExtension(app->id());
399 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]6f371442011-11-09 06:45:46400 EXPECT_FALSE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52401 contents->GetRenderProcessHost()->GetID()));
[email protected]d292d8a2011-05-25 03:47:11402
[email protected]8d3132f62011-10-12 07:13:42403 // Enable app and reload the page.
404 EnableExtension(app->id());
[email protected]a7fe9112012-07-20 02:34:45405 content::WindowedNotificationObserver reload_observer(
[email protected]8d3132f62011-10-12 07:13:42406 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50407 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03408 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10409 chrome::Reload(browser(), CURRENT_TAB);
[email protected]8d3132f62011-10-12 07:13:42410 reload_observer.Wait();
[email protected]6f371442011-11-09 06:45:46411 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52412 contents->GetRenderProcessHost()->GetID()));
[email protected]8d3132f62011-10-12 07:13:42413
414 // Disable app and reload the page.
415 DisableExtension(app->id());
[email protected]a7fe9112012-07-20 02:34:45416 content::WindowedNotificationObserver reload_observer2(
[email protected]8d3132f62011-10-12 07:13:42417 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50418 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03419 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10420 chrome::Reload(browser(), CURRENT_TAB);
[email protected]8d3132f62011-10-12 07:13:42421 reload_observer2.Wait();
[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]8d3132f62011-10-12 07:13:42424
[email protected]d292d8a2011-05-25 03:47:11425 // Enable app and reload via JavaScript.
426 EnableExtension(app->id());
[email protected]a7fe9112012-07-20 02:34:45427 content::WindowedNotificationObserver js_reload_observer(
[email protected]8d3132f62011-10-12 07:13:42428 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50429 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03430 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]7d478cb2012-07-24 17:19:42431 ASSERT_TRUE(content::ExecuteJavaScript(contents->GetRenderViewHost(),
432 L"", L"location.reload();"));
[email protected]8d3132f62011-10-12 07:13:42433 js_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]d292d8a2011-05-25 03:47:11436
437 // Disable app and reload via JavaScript.
438 DisableExtension(app->id());
[email protected]a7fe9112012-07-20 02:34:45439 content::WindowedNotificationObserver js_reload_observer2(
[email protected]8d3132f62011-10-12 07:13:42440 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50441 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03442 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]7d478cb2012-07-24 17:19:42443 ASSERT_TRUE(content::ExecuteJavaScript(contents->GetRenderViewHost(),
444 L"", L"location = location;"));
[email protected]8d3132f62011-10-12 07:13:42445 js_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]d292d8a2011-05-25 03:47:11448}
[email protected]118d3122011-08-10 17:09:53449
[email protected]118d3122011-08-10 17:09:53450// Tests that if we have a non-app process (path3/container.html) that has an
451// iframe with a URL in the app's extent (path1/iframe.html), then opening a
452// link from that iframe to a new window to a URL in the app's extent (path1/
453// empty.html) results in the new window being in an app process. See
454// http://crbug.com/89272 for more details.
[email protected]1f4495b2012-10-12 05:51:05455IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
[email protected]06bdd2b2012-11-30 18:47:13456 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
457 browser()->profile())->extension_service()->process_map();
[email protected]718eab62011-10-05 21:16:52458
[email protected]118d3122011-08-10 17:09:53459 host_resolver()->AddRule("*", "127.0.0.1");
460 ASSERT_TRUE(test_server()->Start());
461
462 GURL base_url = GetTestBaseURL("app_process");
463
464 // Load app and start URL (not in the app).
465 const Extension* app =
466 LoadExtension(test_data_dir_.AppendASCII("app_process"));
467 ASSERT_TRUE(app);
[email protected]19da16a92012-05-23 17:11:29468
[email protected]a7fe9112012-07-20 02:34:45469 content::WindowedNotificationObserver popup_observer(
[email protected]079b3cc2012-09-26 19:59:13470 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
471 content::NotificationService::AllSources());
[email protected]19da16a92012-05-23 17:11:29472 ui_test_utils::NavigateToURL(browser(),
473 base_url.Resolve("path3/container.html"));
[email protected]6f371442011-11-09 06:45:46474 EXPECT_FALSE(process_map->Contains(
[email protected]52877dbc62012-06-29 22:22:03475 chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost()->GetID()));
[email protected]19da16a92012-05-23 17:11:29476 popup_observer.Wait();
[email protected]118d3122011-08-10 17:09:53477
478 // Popup window should be in the app's process.
[email protected]19da16a92012-05-23 17:11:29479 RenderViewHost* popup_host =
480 content::Source<RenderViewHost>(popup_observer.source()).ptr();
481 EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
[email protected]118d3122011-08-10 17:09:53482}
[email protected]a09add52011-08-12 03:59:23483
[email protected]079b3cc2012-09-26 19:59:13484// Similar to the previous test, but ensure that popup blocking bypass
485// isn't granted to the iframe. See crbug.com/117446.
[email protected]1f4495b2012-10-12 05:51:05486#if defined(OS_CHROMEOS)
487// http://crbug.com/153513
488#define MAYBE_OpenAppFromIframe DISABLED_OpenAppFromIframe
489#else
490#define MAYBE_OpenAppFromIframe OpenAppFromIframe
491#endif
492IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
[email protected]079b3cc2012-09-26 19:59:13493 host_resolver()->AddRule("*", "127.0.0.1");
494 ASSERT_TRUE(test_server()->Start());
495
496 // Load app and start URL (not in the app).
497 const Extension* app =
498 LoadExtension(test_data_dir_.AppendASCII("app_process"));
499 ASSERT_TRUE(app);
500
501 content::WindowedNotificationObserver blocker_observer(
502 chrome::NOTIFICATION_CONTENT_BLOCKED_STATE_CHANGED,
503 content::NotificationService::AllSources());
504 ui_test_utils::NavigateToURL(
505 browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
506
507 blocker_observer.Wait();
508
509 WebContents* tab = chrome::GetActiveWebContents(browser());
510 BlockedContentTabHelper* blocked_content_tab_helper =
511 BlockedContentTabHelper::FromWebContents(tab);
512 std::vector<WebContents*> blocked_contents;
513 blocked_content_tab_helper->GetBlockedContents(&blocked_contents);
514 EXPECT_EQ(blocked_contents.size(), 1u);
515}
516
[email protected]88aae972011-12-16 01:14:18517// Tests that if an extension launches an app via chrome.tabs.create with an URL
518// that's not in the app's extent but that redirects to it, we still end up with
519// an app process. See http://crbug.com/99349 for more details.
520IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromExtension) {
521 host_resolver()->AddRule("*", "127.0.0.1");
522 ASSERT_TRUE(StartTestServer());
523
524 LoadExtension(test_data_dir_.AppendASCII("app_process"));
525 const Extension* launcher =
526 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
527
528 // There should be three navigations by the time the app page is loaded.
529 // 1. The extension launcher page.
530 // 2. The URL that the extension launches, which redirects.
531 // 3. The app's URL.
[email protected]5b8ff1c2012-06-02 20:42:20532 content::TestNavigationObserver test_navigation_observer(
533 content::NotificationService::AllSources(),
534 NULL,
535 3);
[email protected]88aae972011-12-16 01:14:18536
537 // Load the launcher extension, which should launch the app.
538 ui_test_utils::NavigateToURLWithDisposition(
539 browser(),
540 launcher->GetResourceURL("main.html"),
541 CURRENT_TAB,
542 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
543
544 // Wait for app tab to be created and loaded.
545 test_navigation_observer.WaitForObservation(
[email protected]729eb632012-07-26 04:45:26546 base::Bind(&content::RunMessageLoop),
[email protected]88aae972011-12-16 01:14:18547 base::Bind(&MessageLoop::Quit,
548 base::Unretained(MessageLoopForUI::current())));
549
550 // App has loaded, and chrome.app.isInstalled should be true.
551 bool is_installed = false;
[email protected]7d478cb2012-07-24 17:19:42552 ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
[email protected]52877dbc62012-06-29 22:22:03553 chrome::GetActiveWebContents(browser())->GetRenderViewHost(), L"",
[email protected]88aae972011-12-16 01:14:18554 L"window.domAutomationController.send(chrome.app.isInstalled)",
555 &is_installed));
556 ASSERT_TRUE(is_installed);
557}
558
[email protected]d55c2382011-08-18 23:10:36559// Tests that if we have an app process (path1/container.html) with a non-app
560// iframe (path3/iframe.html), then opening a link from that iframe to a new
561// window to a same-origin non-app URL (path3/empty.html) should keep the window
562// in the app process.
563// This is in contrast to OpenAppFromIframe, since here the popup will not be
564// missing special permissions and should be scriptable from the iframe.
565// See http://crbug.com/92669 for more details.
[email protected]19da16a92012-05-23 17:11:29566IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
[email protected]06bdd2b2012-11-30 18:47:13567 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
568 browser()->profile())->extension_service()->process_map();
[email protected]718eab62011-10-05 21:16:52569
[email protected]d55c2382011-08-18 23:10:36570 host_resolver()->AddRule("*", "127.0.0.1");
571 ASSERT_TRUE(test_server()->Start());
572
573 GURL base_url = GetTestBaseURL("app_process");
574
575 // Load app and start URL (in the app).
576 const Extension* app =
577 LoadExtension(test_data_dir_.AppendASCII("app_process"));
578 ASSERT_TRUE(app);
[email protected]19da16a92012-05-23 17:11:29579
[email protected]a7fe9112012-07-20 02:34:45580 content::WindowedNotificationObserver popup_observer(
[email protected]19da16a92012-05-23 17:11:29581 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
582 content::NotificationService::AllSources());
583 ui_test_utils::NavigateToURL(browser(),
584 base_url.Resolve("path1/container.html"));
[email protected]f3b1a082011-11-18 00:34:30585 content::RenderProcessHost* process =
[email protected]52877dbc62012-06-29 22:22:03586 chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost();
[email protected]f3b1a082011-11-18 00:34:30587 EXPECT_TRUE(process_map->Contains(process->GetID()));
[email protected]d55c2382011-08-18 23:10:36588
[email protected]19da16a92012-05-23 17:11:29589 // Wait for popup window to appear.
590 popup_observer.Wait();
[email protected]d55c2382011-08-18 23:10:36591
592 // Popup window should be in the app's process.
[email protected]19da16a92012-05-23 17:11:29593 RenderViewHost* popup_host =
594 content::Source<RenderViewHost>(popup_observer.source()).ptr();
595 EXPECT_EQ(process, popup_host->GetProcess());
[email protected]d55c2382011-08-18 23:10:36596}
597
[email protected]a344b762012-03-16 18:53:49598// http://crbug.com/118502
599#if defined(OS_MACOSX) || defined(OS_LINUX)
600#define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
601#else
602#define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
603#endif
604IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
[email protected]06bdd2b2012-11-30 18:47:13605 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
606 browser()->profile())->extension_service()->process_map();
[email protected]6f371442011-11-09 06:45:46607
[email protected]a09add52011-08-12 03:59:23608 host_resolver()->AddRule("*", "127.0.0.1");
609 ASSERT_TRUE(test_server()->Start());
610
611 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
612
613 GURL base_url = GetTestBaseURL("app_process");
614
615 // Load the app, chrome.app.isInstalled should be true.
616 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
[email protected]52877dbc62012-06-29 22:22:03617 WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
[email protected]6f371442011-11-09 06:45:46618 EXPECT_TRUE(process_map->Contains(
[email protected]151a63d2011-12-20 22:32:52619 contents->GetRenderProcessHost()->GetID()));
[email protected]a09add52011-08-12 03:59:23620 bool is_installed = false;
[email protected]7d478cb2012-07-24 17:19:42621 ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52622 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23623 L"window.domAutomationController.send(chrome.app.isInstalled)",
624 &is_installed));
625 ASSERT_TRUE(is_installed);
626
627 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
[email protected]e0f3e142012-07-26 03:31:34628 content::CrashTab(chrome::GetActiveWebContents(browser()));
[email protected]a7fe9112012-07-20 02:34:45629 content::WindowedNotificationObserver observer(
[email protected]ae673742011-08-24 19:48:37630 content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50631 content::Source<NavigationController>(
[email protected]52877dbc62012-06-29 22:22:03632 &chrome::GetActiveWebContents(browser())->GetController()));
[email protected]a37d4b02012-06-25 21:56:10633 chrome::Reload(browser(), CURRENT_TAB);
[email protected]ae673742011-08-24 19:48:37634 observer.Wait();
[email protected]7d478cb2012-07-24 17:19:42635 ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
[email protected]151a63d2011-12-20 22:32:52636 contents->GetRenderViewHost(), L"",
[email protected]a09add52011-08-12 03:59:23637 L"window.domAutomationController.send(chrome.app.isInstalled)",
638 &is_installed));
639 ASSERT_TRUE(is_installed);
640}