1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "chrome/browser/chrome_notification_types.h"
7 #include "chrome/browser/extensions/extension_apitest.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_commands.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "chrome/browser/ui/browser_window.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/test/base/test_switches.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/notification_service.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/site_instance.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "extensions/browser/extension_host.h"
29 #include "extensions/browser/extension_system.h"
30 #include "extensions/browser/install_flag.h"
31 #include "extensions/browser/process_map.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/file_util.h"
34 #include "extensions/common/switches.h"
35 #include "net/dns/mock_host_resolver.h"
36 #include "net/test/embedded_test_server/embedded_test_server.h"
37 #include "sync/api/string_ordinal.h"
39 using content::NavigationController
;
40 using content::RenderViewHost
;
41 using content::SiteInstance
;
42 using content::WebContents
;
43 using extensions::Extension
;
45 class AppApiTest
: public ExtensionApiTest
{
47 // Gets the base URL for files for a specific test, making sure that it uses
48 // "localhost" as the hostname, since that is what the extent is declared
49 // as in the test apps manifests.
50 GURL
GetTestBaseURL(const std::string
& test_directory
) {
51 GURL::Replacements replace_host
;
52 replace_host
.SetHostStr("localhost");
53 GURL base_url
= embedded_test_server()->GetURL(
54 "/extensions/api_test/" + test_directory
+ "/");
55 return base_url
.ReplaceComponents(replace_host
);
58 // Pass flags to make testing apps easier.
59 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
60 ExtensionApiTest::SetUpCommandLine(command_line
);
61 base::CommandLine::ForCurrentProcess()->AppendSwitch(
62 switches::kDisablePopupBlocking
);
63 base::CommandLine::ForCurrentProcess()->AppendSwitch(
64 extensions::switches::kAllowHTTPBackgroundPage
);
67 // Helper function to test that independent tabs of the named app are loaded
68 // into separate processes.
69 void TestAppInstancesHelper(const std::string
& app_name
) {
70 LOG(INFO
) << "Start of test.";
72 extensions::ProcessMap
* process_map
=
73 extensions::ProcessMap::Get(browser()->profile());
75 host_resolver()->AddRule("*", "127.0.0.1");
76 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
78 ASSERT_TRUE(LoadExtension(
79 test_data_dir_
.AppendASCII(app_name
)));
80 const Extension
* extension
= GetSingleLoadedExtension();
82 // Open two tabs in the app, one outside it.
83 GURL base_url
= GetTestBaseURL(app_name
);
85 // Test both opening a URL in a new tab, and opening a tab and then
86 // navigating it. Either way, app tabs should be considered extension
87 // processes, but they have no elevated privileges and thus should not
88 // have WebUI bindings.
89 ui_test_utils::NavigateToURLWithDisposition(
90 browser(), base_url
.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB
,
91 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
92 LOG(INFO
) << "Nav 1.";
93 EXPECT_TRUE(process_map
->Contains(
94 browser()->tab_strip_model()->GetWebContentsAt(1)->
95 GetRenderProcessHost()->GetID()));
96 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
98 content::WindowedNotificationObserver
tab_added_observer(
99 chrome::NOTIFICATION_TAB_ADDED
,
100 content::NotificationService::AllSources());
101 chrome::NewTab(browser());
102 tab_added_observer
.Wait();
103 LOG(INFO
) << "New tab.";
104 ui_test_utils::NavigateToURL(browser(),
105 base_url
.Resolve("path2/empty.html"));
106 LOG(INFO
) << "Nav 2.";
107 EXPECT_TRUE(process_map
->Contains(
108 browser()->tab_strip_model()->GetWebContentsAt(2)->
109 GetRenderProcessHost()->GetID()));
110 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
112 // We should have opened 2 new extension tabs. Including the original blank
113 // tab, we now have 3 tabs. The two app tabs should not be in the same
114 // process, since they do not have the background permission. (Thus, we
115 // want to separate them to improve responsiveness.)
116 ASSERT_EQ(3, browser()->tab_strip_model()->count());
117 WebContents
* tab1
= browser()->tab_strip_model()->GetWebContentsAt(1);
118 WebContents
* tab2
= browser()->tab_strip_model()->GetWebContentsAt(2);
119 EXPECT_NE(tab1
->GetRenderProcessHost(), tab2
->GetRenderProcessHost());
121 // Opening tabs with window.open should keep the page in the opener's
123 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
124 browser()->host_desktop_type()));
125 OpenWindow(tab1
, base_url
.Resolve("path1/empty.html"), true, NULL
);
126 LOG(INFO
) << "WindowOpenHelper 1.";
127 OpenWindow(tab2
, base_url
.Resolve("path2/empty.html"), true, NULL
);
128 LOG(INFO
) << "End of test.";
129 UnloadExtension(extension
->id());
133 // Omits the disable-popup-blocking flag so we can cover that case.
134 class BlockedAppApiTest
: public AppApiTest
{
136 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
137 ExtensionApiTest::SetUpCommandLine(command_line
);
138 base::CommandLine::ForCurrentProcess()->AppendSwitch(
139 extensions::switches::kAllowHTTPBackgroundPage
);
143 // Tests that hosted apps with the background permission get a process-per-app
144 // model, since all pages need to be able to script the background page.
145 // http://crbug.com/172750
146 IN_PROC_BROWSER_TEST_F(AppApiTest
, DISABLED_AppProcess
) {
147 LOG(INFO
) << "Start of test.";
149 extensions::ProcessMap
* process_map
=
150 extensions::ProcessMap::Get(browser()->profile());
152 host_resolver()->AddRule("*", "127.0.0.1");
153 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
155 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("app_process")));
157 LOG(INFO
) << "Loaded extension.";
159 // Open two tabs in the app, one outside it.
160 GURL base_url
= GetTestBaseURL("app_process");
162 // Test both opening a URL in a new tab, and opening a tab and then navigating
163 // it. Either way, app tabs should be considered extension processes, but
164 // they have no elevated privileges and thus should not have WebUI bindings.
165 ui_test_utils::NavigateToURLWithDisposition(
166 browser(), base_url
.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB
,
167 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
168 EXPECT_TRUE(process_map
->Contains(
169 browser()->tab_strip_model()->GetWebContentsAt(1)->
170 GetRenderProcessHost()->GetID()));
171 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
172 LOG(INFO
) << "Nav 1.";
174 ui_test_utils::NavigateToURLWithDisposition(
175 browser(), base_url
.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB
,
176 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
177 EXPECT_TRUE(process_map
->Contains(
178 browser()->tab_strip_model()->GetWebContentsAt(2)->
179 GetRenderProcessHost()->GetID()));
180 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
181 LOG(INFO
) << "Nav 2.";
183 content::WindowedNotificationObserver
tab_added_observer(
184 chrome::NOTIFICATION_TAB_ADDED
,
185 content::NotificationService::AllSources());
186 chrome::NewTab(browser());
187 tab_added_observer
.Wait();
188 LOG(INFO
) << "New tab.";
189 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path3/empty.html"));
190 LOG(INFO
) << "Nav 3.";
191 EXPECT_FALSE(process_map
->Contains(
192 browser()->tab_strip_model()->GetWebContentsAt(3)->
193 GetRenderProcessHost()->GetID()));
194 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(3)->GetWebUI());
196 // We should have opened 3 new extension tabs. Including the original blank
197 // tab, we now have 4 tabs. Because the app_process app has the background
198 // permission, all of its instances are in the same process. Thus two tabs
199 // should be part of the extension app and grouped in the same process.
200 ASSERT_EQ(4, browser()->tab_strip_model()->count());
201 WebContents
* tab
= browser()->tab_strip_model()->GetWebContentsAt(1);
203 EXPECT_EQ(tab
->GetRenderProcessHost(),
204 browser()->tab_strip_model()->GetWebContentsAt(2)->
205 GetRenderProcessHost());
206 EXPECT_NE(tab
->GetRenderProcessHost(),
207 browser()->tab_strip_model()->GetWebContentsAt(3)->
208 GetRenderProcessHost());
210 // Now let's do the same using window.open. The same should happen.
211 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
212 browser()->host_desktop_type()));
213 OpenWindow(tab
, base_url
.Resolve("path1/empty.html"), true, NULL
);
214 LOG(INFO
) << "WindowOpenHelper 1.";
215 OpenWindow(tab
, base_url
.Resolve("path2/empty.html"), true, NULL
);
216 LOG(INFO
) << "WindowOpenHelper 2.";
217 // TODO(creis): This should open in a new process (i.e., false for the last
218 // argument), but we temporarily avoid swapping processes away from a hosted
219 // app if it has an opener, because some OAuth providers make script calls
220 // between non-app popups and non-app iframes in the app process.
221 // See crbug.com/59285.
222 OpenWindow(tab
, base_url
.Resolve("path3/empty.html"), true, NULL
);
223 LOG(INFO
) << "WindowOpenHelper 3.";
225 // Now let's have these pages navigate, into or out of the extension web
226 // extent. They should switch processes.
227 const GURL
& app_url(base_url
.Resolve("path1/empty.html"));
228 const GURL
& non_app_url(base_url
.Resolve("path3/empty.html"));
229 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
231 LOG(INFO
) << "NavigateTabHelper 1.";
232 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(3),
234 LOG(INFO
) << "NavigateTabHelper 2.";
235 EXPECT_NE(tab
->GetRenderProcessHost(),
236 browser()->tab_strip_model()->GetWebContentsAt(2)->
237 GetRenderProcessHost());
238 EXPECT_EQ(tab
->GetRenderProcessHost(),
239 browser()->tab_strip_model()->GetWebContentsAt(3)->
240 GetRenderProcessHost());
242 // If one of the popup tabs navigates back to the app, window.opener should
244 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(6),
246 LOG(INFO
) << "NavigateTabHelper 3.";
247 EXPECT_EQ(tab
->GetRenderProcessHost(),
248 browser()->tab_strip_model()->GetWebContentsAt(6)->
249 GetRenderProcessHost());
250 bool windowOpenerValid
= false;
251 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
252 browser()->tab_strip_model()->GetWebContentsAt(6),
253 "window.domAutomationController.send(window.opener != null)",
254 &windowOpenerValid
));
255 ASSERT_TRUE(windowOpenerValid
);
257 LOG(INFO
) << "End of test.";
260 // Test that hosted apps without the background permission use a process per app
261 // instance model, such that separate instances are in separate processes.
262 // Flaky on Windows. http://crbug.com/248047
264 #define MAYBE_AppProcessInstances DISABLED_AppProcessInstances
266 #define MAYBE_AppProcessInstances AppProcessInstances
268 IN_PROC_BROWSER_TEST_F(AppApiTest
, MAYBE_AppProcessInstances
) {
269 TestAppInstancesHelper("app_process_instances");
272 // Test that hosted apps with the background permission but that set
273 // allow_js_access to false also use a process per app instance model.
274 // Separate instances should be in separate processes.
275 // Flaky on XP: http://crbug.com/165834
277 #define MAYBE_AppProcessBackgroundInstances \
278 DISABLED_AppProcessBackgroundInstances
280 #define MAYBE_AppProcessBackgroundInstances AppProcessBackgroundInstances
282 IN_PROC_BROWSER_TEST_F(AppApiTest
, MAYBE_AppProcessBackgroundInstances
) {
283 TestAppInstancesHelper("app_process_background_instances");
286 // Tests that bookmark apps do not use the app process model and are treated
287 // like normal web pages instead. http://crbug.com/104636.
288 // Timing out on Windows. http://crbug.com/238777
290 #define MAYBE_BookmarkAppGetsNormalProcess DISABLED_BookmarkAppGetsNormalProcess
292 #define MAYBE_BookmarkAppGetsNormalProcess BookmarkAppGetsNormalProcess
294 IN_PROC_BROWSER_TEST_F(AppApiTest
, MAYBE_BookmarkAppGetsNormalProcess
) {
295 ExtensionService
* service
= extensions::ExtensionSystem::Get(
296 browser()->profile())->extension_service();
297 extensions::ProcessMap
* process_map
=
298 extensions::ProcessMap::Get(browser()->profile());
300 host_resolver()->AddRule("*", "127.0.0.1");
301 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
302 GURL base_url
= GetTestBaseURL("app_process");
304 // Load an app as a bookmark app.
306 scoped_refptr
<const Extension
> extension(extensions::file_util::LoadExtension(
307 test_data_dir_
.AppendASCII("app_process"),
308 extensions::Manifest::UNPACKED
,
309 Extension::FROM_BOOKMARK
,
311 service
->OnExtensionInstalled(extension
.get(),
312 syncer::StringOrdinal::CreateInitialOrdinal(),
313 extensions::kInstallFlagInstallImmediately
);
314 ASSERT_TRUE(extension
.get());
315 ASSERT_TRUE(extension
->from_bookmark());
317 // Test both opening a URL in a new tab, and opening a tab and then navigating
318 // it. Either way, bookmark app tabs should be considered normal processes
319 // with no elevated privileges and no WebUI bindings.
320 ui_test_utils::NavigateToURLWithDisposition(
321 browser(), base_url
.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB
,
322 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
323 EXPECT_FALSE(process_map
->Contains(
324 browser()->tab_strip_model()->GetWebContentsAt(1)->
325 GetRenderProcessHost()->GetID()));
326 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
328 content::WindowedNotificationObserver
tab_added_observer(
329 chrome::NOTIFICATION_TAB_ADDED
,
330 content::NotificationService::AllSources());
331 chrome::NewTab(browser());
332 tab_added_observer
.Wait();
333 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path2/empty.html"));
334 EXPECT_FALSE(process_map
->Contains(
335 browser()->tab_strip_model()->GetWebContentsAt(2)->
336 GetRenderProcessHost()->GetID()));
337 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
339 // We should have opened 2 new bookmark app tabs. Including the original blank
340 // tab, we now have 3 tabs. Because normal pages use the
341 // process-per-site-instance model, each should be in its own process.
342 ASSERT_EQ(3, browser()->tab_strip_model()->count());
343 WebContents
* tab
= browser()->tab_strip_model()->GetWebContentsAt(1);
344 EXPECT_NE(tab
->GetRenderProcessHost(),
345 browser()->tab_strip_model()->GetWebContentsAt(2)->
346 GetRenderProcessHost());
348 // Now let's do the same using window.open. The same should happen.
349 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
350 browser()->host_desktop_type()));
351 OpenWindow(tab
, base_url
.Resolve("path1/empty.html"), true, NULL
);
352 OpenWindow(tab
, base_url
.Resolve("path2/empty.html"), true, NULL
);
354 // Now let's have a tab navigate out of and back into the app's web
355 // extent. Neither navigation should switch processes.
356 const GURL
& app_url(base_url
.Resolve("path1/empty.html"));
357 const GURL
& non_app_url(base_url
.Resolve("path3/empty.html"));
358 RenderViewHost
* host2
=
359 browser()->tab_strip_model()->GetWebContentsAt(2)->GetRenderViewHost();
360 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
362 EXPECT_EQ(host2
->GetProcess(),
363 browser()->tab_strip_model()->GetWebContentsAt(2)->
364 GetRenderProcessHost());
365 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
367 EXPECT_EQ(host2
->GetProcess(),
368 browser()->tab_strip_model()->GetWebContentsAt(2)->
369 GetRenderProcessHost());
372 // Tests that app process switching works properly in the following scenario:
373 // 1. navigate to a page1 in the app
374 // 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
375 // 3. page2 redirects back to a page in the app
376 // The final navigation should end up in the app process.
377 // See http://crbug.com/61757
378 // Flaky. http://crbug.com/341898
379 IN_PROC_BROWSER_TEST_F(AppApiTest
, DISABLED_AppProcessRedirectBack
) {
380 host_resolver()->AddRule("*", "127.0.0.1");
381 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
383 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("app_process")));
385 // Open two tabs in the app.
386 GURL base_url
= GetTestBaseURL("app_process");
388 chrome::NewTab(browser());
389 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
390 chrome::NewTab(browser());
391 // Wait until the second tab finishes its redirect train (2 hops).
392 // 1. We navigate to redirect.html
393 // 2. Renderer navigates and finishes, counting as a load stop.
394 // 3. Renderer issues the meta refresh to navigate to server-redirect.
395 // 4. Renderer is now in a "provisional load", waiting for navigation to
397 // 5. Browser sees a redirect response from server-redirect to empty.html, and
398 // transfers that to a new navigation, using RequestTransferURL.
399 // 6. Renderer navigates to empty.html, and finishes loading, counting as the
401 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
402 browser(), base_url
.Resolve("path1/redirect.html"), 2);
404 // 3 tabs, including the initial about:blank. The last 2 should be the same
406 ASSERT_EQ(3, browser()->tab_strip_model()->count());
407 EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
408 browser()->tab_strip_model()->GetWebContentsAt(2)->
409 GetController().GetLastCommittedEntry()->GetURL().path());
410 EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
411 GetRenderProcessHost(),
412 browser()->tab_strip_model()->GetWebContentsAt(2)->
413 GetRenderProcessHost());
416 // Ensure that re-navigating to a URL after installing or uninstalling it as an
417 // app correctly swaps the tab to the app process. (http://crbug.com/80621)
419 // Fails on Windows. http://crbug.com/238670
420 // Added logging to help diagnose the location of the problem.
421 IN_PROC_BROWSER_TEST_F(AppApiTest
, NavigateIntoAppProcess
) {
422 extensions::ProcessMap
* process_map
=
423 extensions::ProcessMap::Get(browser()->profile());
425 host_resolver()->AddRule("*", "127.0.0.1");
426 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
428 // The app under test acts on URLs whose host is "localhost",
429 // so the URLs we navigate to must have host "localhost".
430 GURL base_url
= GetTestBaseURL("app_process");
432 // Load an app URL before loading the app.
433 LOG(INFO
) << "Loading path1/empty.html.";
434 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
435 LOG(INFO
) << "Loading path1/empty.html - done.";
436 WebContents
* contents
= browser()->tab_strip_model()->GetWebContentsAt(0);
437 EXPECT_FALSE(process_map
->Contains(
438 contents
->GetRenderProcessHost()->GetID()));
440 // Load app and re-navigate to the page.
441 LOG(INFO
) << "Loading extension.";
442 const Extension
* app
=
443 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
444 LOG(INFO
) << "Loading extension - done.";
446 LOG(INFO
) << "Loading path1/empty.html.";
447 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
448 LOG(INFO
) << "Loading path1/empty.html - done.";
449 EXPECT_TRUE(process_map
->Contains(
450 contents
->GetRenderProcessHost()->GetID()));
452 // Disable app and re-navigate to the page.
453 LOG(INFO
) << "Disabling extension.";
454 DisableExtension(app
->id());
455 LOG(INFO
) << "Disabling extension - done.";
456 LOG(INFO
) << "Loading path1/empty.html.";
457 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
458 LOG(INFO
) << "Loading path1/empty.html - done.";
459 EXPECT_FALSE(process_map
->Contains(
460 contents
->GetRenderProcessHost()->GetID()));
463 // Ensure that reloading a URL after installing or uninstalling it as an app
464 // correctly swaps the tab to the app process. (http://crbug.com/80621)
466 // Added logging to help diagnose the location of the problem.
467 // http://crbug.com/238670
468 IN_PROC_BROWSER_TEST_F(AppApiTest
, ReloadIntoAppProcess
) {
469 extensions::ProcessMap
* process_map
=
470 extensions::ProcessMap::Get(browser()->profile());
472 host_resolver()->AddRule("*", "127.0.0.1");
473 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
475 // The app under test acts on URLs whose host is "localhost",
476 // so the URLs we navigate to must have host "localhost".
477 GURL base_url
= GetTestBaseURL("app_process");
479 // Load app, disable it, and navigate to the page.
480 LOG(INFO
) << "Loading extension.";
481 const Extension
* app
=
482 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
483 LOG(INFO
) << "Loading extension - done.";
485 LOG(INFO
) << "Disabling extension.";
486 DisableExtension(app
->id());
487 LOG(INFO
) << "Disabling extension - done.";
488 LOG(INFO
) << "Navigate to path1/empty.html.";
489 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
490 LOG(INFO
) << "Navigate to path1/empty.html - done.";
491 WebContents
* contents
= browser()->tab_strip_model()->GetWebContentsAt(0);
492 EXPECT_FALSE(process_map
->Contains(
493 contents
->GetRenderProcessHost()->GetID()));
495 // Enable app and reload the page.
496 LOG(INFO
) << "Enabling extension.";
497 EnableExtension(app
->id());
498 LOG(INFO
) << "Enabling extension - done.";
499 content::WindowedNotificationObserver
reload_observer(
500 content::NOTIFICATION_LOAD_STOP
,
501 content::Source
<NavigationController
>(
502 &browser()->tab_strip_model()->GetActiveWebContents()->
504 LOG(INFO
) << "Reloading.";
505 chrome::Reload(browser(), CURRENT_TAB
);
506 reload_observer
.Wait();
507 LOG(INFO
) << "Reloading - done.";
508 EXPECT_TRUE(process_map
->Contains(
509 contents
->GetRenderProcessHost()->GetID()));
511 // Disable app and reload the page.
512 LOG(INFO
) << "Disabling extension.";
513 DisableExtension(app
->id());
514 LOG(INFO
) << "Disabling extension - done.";
515 content::WindowedNotificationObserver
reload_observer2(
516 content::NOTIFICATION_LOAD_STOP
,
517 content::Source
<NavigationController
>(
518 &browser()->tab_strip_model()->GetActiveWebContents()->
520 LOG(INFO
) << "Reloading.";
521 chrome::Reload(browser(), CURRENT_TAB
);
522 reload_observer2
.Wait();
523 LOG(INFO
) << "Reloading - done.";
524 EXPECT_FALSE(process_map
->Contains(
525 contents
->GetRenderProcessHost()->GetID()));
528 // Ensure that reloading a URL with JavaScript after installing or uninstalling
529 // it as an app correctly swaps the process. (http://crbug.com/80621)
531 // Crashes on Windows and Mac. http://crbug.com/238670
532 // Added logging to help diagnose the location of the problem.
533 IN_PROC_BROWSER_TEST_F(AppApiTest
, ReloadIntoAppProcessWithJavaScript
) {
534 extensions::ProcessMap
* process_map
=
535 extensions::ProcessMap::Get(browser()->profile());
537 host_resolver()->AddRule("*", "127.0.0.1");
538 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
540 // The app under test acts on URLs whose host is "localhost",
541 // so the URLs we navigate to must have host "localhost".
542 GURL base_url
= GetTestBaseURL("app_process");
544 // Load app, disable it, and navigate to the page.
545 LOG(INFO
) << "Loading extension.";
546 const Extension
* app
=
547 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
548 LOG(INFO
) << "Loading extension - done.";
550 LOG(INFO
) << "Disabling extension.";
551 DisableExtension(app
->id());
552 LOG(INFO
) << "Disabling extension - done.";
553 LOG(INFO
) << "Navigate to path1/empty.html.";
554 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
555 LOG(INFO
) << "Navigate to path1/empty.html - done.";
556 WebContents
* contents
= browser()->tab_strip_model()->GetWebContentsAt(0);
557 EXPECT_FALSE(process_map
->Contains(
558 contents
->GetRenderProcessHost()->GetID()));
560 // Enable app and reload via JavaScript.
561 LOG(INFO
) << "Enabling extension.";
562 EnableExtension(app
->id());
563 LOG(INFO
) << "Enabling extension - done.";
564 content::WindowedNotificationObserver
js_reload_observer(
565 content::NOTIFICATION_LOAD_STOP
,
566 content::Source
<NavigationController
>(
567 &browser()->tab_strip_model()->GetActiveWebContents()->
569 LOG(INFO
) << "Executing location.reload().";
570 ASSERT_TRUE(content::ExecuteScript(contents
, "location.reload();"));
571 js_reload_observer
.Wait();
572 LOG(INFO
) << "Executing location.reload() - done.";
573 EXPECT_TRUE(process_map
->Contains(
574 contents
->GetRenderProcessHost()->GetID()));
576 // Disable app and reload via JavaScript.
577 LOG(INFO
) << "Disabling extension.";
578 DisableExtension(app
->id());
579 LOG(INFO
) << "Disabling extension - done.";
580 content::WindowedNotificationObserver
js_reload_observer2(
581 content::NOTIFICATION_LOAD_STOP
,
582 content::Source
<NavigationController
>(
583 &browser()->tab_strip_model()->GetActiveWebContents()->
585 LOG(INFO
) << "Executing location = location.";
586 ASSERT_TRUE(content::ExecuteScript(contents
, "location = location;"));
587 js_reload_observer2
.Wait();
588 LOG(INFO
) << "Executing location = location - done.";
589 EXPECT_FALSE(process_map
->Contains(
590 contents
->GetRenderProcessHost()->GetID()));
593 // Tests that if we have a non-app process (path3/container.html) that has an
594 // iframe with a URL in the app's extent (path1/iframe.html), then opening a
595 // link from that iframe to a new window to a URL in the app's extent (path1/
596 // empty.html) results in the new window being in an app process. See
597 // http://crbug.com/89272 for more details.
598 IN_PROC_BROWSER_TEST_F(AppApiTest
, OpenAppFromIframe
) {
599 #if defined(OS_WIN) && defined(USE_ASH)
600 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
601 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
602 switches::kAshBrowserTests
))
606 extensions::ProcessMap
* process_map
=
607 extensions::ProcessMap::Get(browser()->profile());
609 host_resolver()->AddRule("*", "127.0.0.1");
610 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
612 GURL base_url
= GetTestBaseURL("app_process");
614 // Load app and start URL (not in the app).
615 const Extension
* app
=
616 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
619 ui_test_utils::NavigateToURL(browser(),
620 base_url
.Resolve("path3/container.html"));
621 EXPECT_FALSE(process_map
->Contains(
622 browser()->tab_strip_model()->GetWebContentsAt(0)->
623 GetRenderProcessHost()->GetID()));
625 const BrowserList
* active_browser_list
=
626 BrowserList::GetInstance(chrome::GetActiveDesktop());
627 EXPECT_EQ(2U, active_browser_list
->size());
628 content::WebContents
* popup_contents
=
629 active_browser_list
->get(1)->tab_strip_model()->GetActiveWebContents();
630 content::WaitForLoadStop(popup_contents
);
632 // Popup window should be in the app's process.
633 RenderViewHost
* popup_host
= popup_contents
->GetRenderViewHost();
634 EXPECT_TRUE(process_map
->Contains(popup_host
->GetProcess()->GetID()));
637 // Similar to the previous test, but ensure that popup blocking bypass
638 // isn't granted to the iframe. See crbug.com/117446.
639 #if defined(OS_CHROMEOS)
640 // http://crbug.com/153513
641 #define MAYBE_OpenAppFromIframe DISABLED_OpenAppFromIframe
643 #define MAYBE_OpenAppFromIframe OpenAppFromIframe
645 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest
, MAYBE_OpenAppFromIframe
) {
646 host_resolver()->AddRule("*", "127.0.0.1");
647 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
649 // Load app and start URL (not in the app).
650 const Extension
* app
=
651 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
654 ui_test_utils::NavigateToURL(
655 browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
657 WebContents
* tab
= browser()->tab_strip_model()->GetActiveWebContents();
658 PopupBlockerTabHelper
* popup_blocker_tab_helper
=
659 PopupBlockerTabHelper::FromWebContents(tab
);
660 if (!popup_blocker_tab_helper
->GetBlockedPopupsCount()) {
661 content::WindowedNotificationObserver
observer(
662 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
663 content::NotificationService::AllSources());
667 EXPECT_EQ(1u, popup_blocker_tab_helper
->GetBlockedPopupsCount());
670 // Tests that if an extension launches an app via chrome.tabs.create with an URL
671 // that's not in the app's extent but that server redirects to it, we still end
672 // up with an app process. See http://crbug.com/99349 for more details.
673 IN_PROC_BROWSER_TEST_F(AppApiTest
, ServerRedirectToAppFromExtension
) {
674 host_resolver()->AddRule("*", "127.0.0.1");
675 ASSERT_TRUE(StartEmbeddedTestServer());
677 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
678 const Extension
* launcher
=
679 LoadExtension(test_data_dir_
.AppendASCII("app_launcher"));
681 // There should be two navigations by the time the app page is loaded.
682 // 1. The extension launcher page.
683 // 2. The app's URL (which includes a server redirect).
684 // Note that the server redirect does not generate a navigation event.
685 content::TestNavigationObserver
test_navigation_observer(
686 browser()->tab_strip_model()->GetActiveWebContents(),
688 test_navigation_observer
.StartWatchingNewWebContents();
690 // Load the launcher extension, which should launch the app.
691 ui_test_utils::NavigateToURL(
692 browser(), launcher
->GetResourceURL("server_redirect.html"));
694 // Wait for app tab to be created and loaded.
695 test_navigation_observer
.Wait();
697 // App has loaded, and chrome.app.isInstalled should be true.
698 bool is_installed
= false;
699 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
700 browser()->tab_strip_model()->GetActiveWebContents(),
701 "window.domAutomationController.send(chrome.app.isInstalled)",
703 ASSERT_TRUE(is_installed
);
706 // Tests that if an extension launches an app via chrome.tabs.create with an URL
707 // that's not in the app's extent but that client redirects to it, we still end
708 // up with an app process.
709 IN_PROC_BROWSER_TEST_F(AppApiTest
, ClientRedirectToAppFromExtension
) {
710 host_resolver()->AddRule("*", "127.0.0.1");
711 ASSERT_TRUE(StartEmbeddedTestServer());
713 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
714 const Extension
* launcher
=
715 LoadExtension(test_data_dir_
.AppendASCII("app_launcher"));
717 // There should be three navigations by the time the app page is loaded.
718 // 1. The extension launcher page.
719 // 2. The URL that the extension launches, which client redirects.
721 content::TestNavigationObserver
test_navigation_observer(
722 browser()->tab_strip_model()->GetActiveWebContents(),
724 test_navigation_observer
.StartWatchingNewWebContents();
726 // Load the launcher extension, which should launch the app.
727 ui_test_utils::NavigateToURL(
728 browser(), launcher
->GetResourceURL("client_redirect.html"));
730 // Wait for app tab to be created and loaded.
731 test_navigation_observer
.Wait();
733 // App has loaded, and chrome.app.isInstalled should be true.
734 bool is_installed
= false;
735 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
736 browser()->tab_strip_model()->GetActiveWebContents(),
737 "window.domAutomationController.send(chrome.app.isInstalled)",
739 ASSERT_TRUE(is_installed
);
742 // Tests that if we have an app process (path1/container.html) with a non-app
743 // iframe (path3/iframe.html), then opening a link from that iframe to a new
744 // window to a same-origin non-app URL (path3/empty.html) should keep the window
745 // in the app process.
746 // This is in contrast to OpenAppFromIframe, since here the popup will not be
747 // missing special permissions and should be scriptable from the iframe.
748 // See http://crbug.com/92669 for more details.
749 IN_PROC_BROWSER_TEST_F(AppApiTest
, OpenWebPopupFromWebIframe
) {
750 extensions::ProcessMap
* process_map
=
751 extensions::ProcessMap::Get(browser()->profile());
753 host_resolver()->AddRule("*", "127.0.0.1");
754 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
756 GURL base_url
= GetTestBaseURL("app_process");
758 // Load app and start URL (in the app).
759 const Extension
* app
=
760 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
763 ui_test_utils::NavigateToURL(browser(),
764 base_url
.Resolve("path1/container.html"));
765 content::RenderProcessHost
* process
=
766 browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
767 EXPECT_TRUE(process_map
->Contains(process
->GetID()));
769 // Popup window should be in the app's process if site isolation is off;
770 // otherwise they should be in different processes.
771 const BrowserList
* active_browser_list
=
772 BrowserList::GetInstance(chrome::GetActiveDesktop());
773 EXPECT_EQ(2U, active_browser_list
->size());
774 content::WebContents
* popup_contents
=
775 active_browser_list
->get(1)->tab_strip_model()->GetActiveWebContents();
776 content::WaitForLoadStop(popup_contents
);
778 bool should_be_in_same_process
=
779 !base::CommandLine::ForCurrentProcess()->HasSwitch(
780 switches::kSitePerProcess
);
781 content::RenderProcessHost
* popup_process
=
782 popup_contents
->GetRenderProcessHost();
783 EXPECT_EQ(should_be_in_same_process
, process
== popup_process
);
784 EXPECT_EQ(should_be_in_same_process
,
785 process_map
->Contains(popup_process
->GetID()));
788 // http://crbug.com/118502
789 #if defined(OS_MACOSX) || defined(OS_LINUX)
790 #define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
792 #define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
794 IN_PROC_BROWSER_TEST_F(AppApiTest
, MAYBE_ReloadAppAfterCrash
) {
795 extensions::ProcessMap
* process_map
=
796 extensions::ProcessMap::Get(browser()->profile());
798 host_resolver()->AddRule("*", "127.0.0.1");
799 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
801 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("app_process")));
803 GURL base_url
= GetTestBaseURL("app_process");
805 // Load the app, chrome.app.isInstalled should be true.
806 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("path1/empty.html"));
807 WebContents
* contents
= browser()->tab_strip_model()->GetWebContentsAt(0);
808 EXPECT_TRUE(process_map
->Contains(
809 contents
->GetRenderProcessHost()->GetID()));
810 bool is_installed
= false;
811 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
813 "window.domAutomationController.send(chrome.app.isInstalled)",
815 ASSERT_TRUE(is_installed
);
817 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
818 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
819 content::WindowedNotificationObserver
observer(
820 content::NOTIFICATION_LOAD_STOP
,
821 content::Source
<NavigationController
>(
822 &browser()->tab_strip_model()->GetActiveWebContents()->
824 chrome::Reload(browser(), CURRENT_TAB
);
826 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
828 "window.domAutomationController.send(chrome.app.isInstalled)",
830 ASSERT_TRUE(is_installed
);
833 // Test that a cross-process navigation away from a hosted app stays in the same
834 // BrowsingInstance, so that postMessage calls to the app's other windows still
836 IN_PROC_BROWSER_TEST_F(AppApiTest
, SameBrowsingInstanceAfterSwap
) {
837 extensions::ProcessMap
* process_map
=
838 extensions::ProcessMap::Get(browser()->profile());
840 host_resolver()->AddRule("*", "127.0.0.1");
841 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
843 GURL base_url
= GetTestBaseURL("app_process");
845 // Load app and start URL (in the app).
846 const Extension
* app
=
847 LoadExtension(test_data_dir_
.AppendASCII("app_process"));
850 ui_test_utils::NavigateToURL(browser(),
851 base_url
.Resolve("path1/iframe.html"));
852 content::SiteInstance
* app_instance
=
853 browser()->tab_strip_model()->GetWebContentsAt(0)->GetSiteInstance();
854 EXPECT_TRUE(process_map
->Contains(app_instance
->GetProcess()->GetID()));
856 // Popup window should be in the app's process.
857 const BrowserList
* active_browser_list
=
858 BrowserList::GetInstance(chrome::GetActiveDesktop());
859 EXPECT_EQ(2U, active_browser_list
->size());
860 content::WebContents
* popup_contents
=
861 active_browser_list
->get(1)->tab_strip_model()->GetActiveWebContents();
862 content::WaitForLoadStop(popup_contents
);
864 SiteInstance
* popup_instance
= popup_contents
->GetSiteInstance();
865 EXPECT_EQ(app_instance
, popup_instance
);
867 // Navigate the popup to another process outside the app.
868 GURL
non_app_url(base_url
.Resolve("path3/empty.html"));
869 ui_test_utils::NavigateToURL(active_browser_list
->get(1), non_app_url
);
870 SiteInstance
* new_instance
= popup_contents
->GetSiteInstance();
871 EXPECT_NE(app_instance
, new_instance
);
873 // It should still be in the same BrowsingInstance, allowing postMessage to
875 EXPECT_TRUE(app_instance
->IsRelatedSiteInstance(new_instance
));