Make default apps cache multiprofile friendly
[chromium-blink-merge.git] / chrome / browser / extensions / app_process_apitest.cc
blob380ba1ce4610b6b991d4d0bfa735ab7636321b38
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_host.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/extensions/process_map.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/extensions/extension_file_util.h"
23 #include "chrome/test/base/test_switches.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "content/public/test/test_navigation_observer.h"
32 #include "net/dns/mock_host_resolver.h"
33 #include "net/test/embedded_test_server/embedded_test_server.h"
34 #include "sync/api/string_ordinal.h"
36 using content::NavigationController;
37 using content::RenderViewHost;
38 using content::WebContents;
39 using extensions::Extension;
41 class AppApiTest : public ExtensionApiTest {
42 protected:
43 // Gets the base URL for files for a specific test, making sure that it uses
44 // "localhost" as the hostname, since that is what the extent is declared
45 // as in the test apps manifests.
46 GURL GetTestBaseURL(std::string test_directory) {
47 GURL::Replacements replace_host;
48 std::string host_str("localhost"); // must stay in scope with replace_host
49 replace_host.SetHostStr(host_str);
50 GURL base_url = embedded_test_server()->GetURL(
51 "/extensions/api_test/" + test_directory + "/");
52 return base_url.ReplaceComponents(replace_host);
55 // Pass flags to make testing apps easier.
56 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
57 ExtensionApiTest::SetUpCommandLine(command_line);
58 CommandLine::ForCurrentProcess()->AppendSwitch(
59 switches::kDisablePopupBlocking);
60 CommandLine::ForCurrentProcess()->AppendSwitch(
61 switches::kAllowHTTPBackgroundPage);
64 // Helper function to test that independent tabs of the named app are loaded
65 // into separate processes.
66 void TestAppInstancesHelper(std::string app_name) {
67 LOG(INFO) << "Start of test.";
69 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
70 browser()->profile())->extension_service()->process_map();
72 host_resolver()->AddRule("*", "127.0.0.1");
73 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
75 ASSERT_TRUE(LoadExtension(
76 test_data_dir_.AppendASCII(app_name)));
77 const Extension* extension = GetSingleLoadedExtension();
79 // Open two tabs in the app, one outside it.
80 GURL base_url = GetTestBaseURL(app_name);
82 // Test both opening a URL in a new tab, and opening a tab and then
83 // navigating it. Either way, app tabs should be considered extension
84 // processes, but they have no elevated privileges and thus should not
85 // have WebUI bindings.
86 ui_test_utils::NavigateToURLWithDisposition(
87 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
88 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
89 LOG(INFO) << "Nav 1.";
90 EXPECT_TRUE(process_map->Contains(
91 browser()->tab_strip_model()->GetWebContentsAt(1)->
92 GetRenderProcessHost()->GetID()));
93 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
95 content::WindowedNotificationObserver tab_added_observer(
96 chrome::NOTIFICATION_TAB_ADDED,
97 content::NotificationService::AllSources());
98 chrome::NewTab(browser());
99 tab_added_observer.Wait();
100 LOG(INFO) << "New tab.";
101 ui_test_utils::NavigateToURL(browser(),
102 base_url.Resolve("path2/empty.html"));
103 LOG(INFO) << "Nav 2.";
104 EXPECT_TRUE(process_map->Contains(
105 browser()->tab_strip_model()->GetWebContentsAt(2)->
106 GetRenderProcessHost()->GetID()));
107 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
109 // We should have opened 2 new extension tabs. Including the original blank
110 // tab, we now have 3 tabs. The two app tabs should not be in the same
111 // process, since they do not have the background permission. (Thus, we
112 // want to separate them to improve responsiveness.)
113 ASSERT_EQ(3, browser()->tab_strip_model()->count());
114 WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(1);
115 WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(2);
116 EXPECT_NE(tab1->GetRenderProcessHost(), tab2->GetRenderProcessHost());
118 // Opening tabs with window.open should keep the page in the opener's
119 // process.
120 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
121 browser()->host_desktop_type()));
122 OpenWindow(tab1, base_url.Resolve("path1/empty.html"), true, NULL);
123 LOG(INFO) << "WindowOpenHelper 1.";
124 OpenWindow(tab2, base_url.Resolve("path2/empty.html"), true, NULL);
125 LOG(INFO) << "End of test.";
126 UnloadExtension(extension->id());
130 // Omits the disable-popup-blocking flag so we can cover that case.
131 class BlockedAppApiTest : public AppApiTest {
132 protected:
133 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
134 ExtensionApiTest::SetUpCommandLine(command_line);
135 CommandLine::ForCurrentProcess()->AppendSwitch(
136 switches::kAllowHTTPBackgroundPage);
140 // Tests that hosted apps with the background permission get a process-per-app
141 // model, since all pages need to be able to script the background page.
142 // http://crbug.com/172750
143 IN_PROC_BROWSER_TEST_F(AppApiTest, DISABLED_AppProcess) {
144 LOG(INFO) << "Start of test.";
146 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
147 browser()->profile())->extension_service()->process_map();
149 host_resolver()->AddRule("*", "127.0.0.1");
150 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
152 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
154 LOG(INFO) << "Loaded extension.";
156 // Open two tabs in the app, one outside it.
157 GURL base_url = GetTestBaseURL("app_process");
159 // Test both opening a URL in a new tab, and opening a tab and then navigating
160 // it. Either way, app tabs should be considered extension processes, but
161 // they have no elevated privileges and thus should not have WebUI bindings.
162 ui_test_utils::NavigateToURLWithDisposition(
163 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
164 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
165 EXPECT_TRUE(process_map->Contains(
166 browser()->tab_strip_model()->GetWebContentsAt(1)->
167 GetRenderProcessHost()->GetID()));
168 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
169 LOG(INFO) << "Nav 1.";
171 ui_test_utils::NavigateToURLWithDisposition(
172 browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
173 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
174 EXPECT_TRUE(process_map->Contains(
175 browser()->tab_strip_model()->GetWebContentsAt(2)->
176 GetRenderProcessHost()->GetID()));
177 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
178 LOG(INFO) << "Nav 2.";
180 content::WindowedNotificationObserver tab_added_observer(
181 chrome::NOTIFICATION_TAB_ADDED,
182 content::NotificationService::AllSources());
183 chrome::NewTab(browser());
184 tab_added_observer.Wait();
185 LOG(INFO) << "New tab.";
186 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
187 LOG(INFO) << "Nav 3.";
188 EXPECT_FALSE(process_map->Contains(
189 browser()->tab_strip_model()->GetWebContentsAt(3)->
190 GetRenderProcessHost()->GetID()));
191 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(3)->GetWebUI());
193 // We should have opened 3 new extension tabs. Including the original blank
194 // tab, we now have 4 tabs. Because the app_process app has the background
195 // permission, all of its instances are in the same process. Thus two tabs
196 // should be part of the extension app and grouped in the same process.
197 ASSERT_EQ(4, browser()->tab_strip_model()->count());
198 WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
200 EXPECT_EQ(tab->GetRenderProcessHost(),
201 browser()->tab_strip_model()->GetWebContentsAt(2)->
202 GetRenderProcessHost());
203 EXPECT_NE(tab->GetRenderProcessHost(),
204 browser()->tab_strip_model()->GetWebContentsAt(3)->
205 GetRenderProcessHost());
207 // Now let's do the same using window.open. The same should happen.
208 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
209 browser()->host_desktop_type()));
210 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
211 LOG(INFO) << "WindowOpenHelper 1.";
212 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
213 LOG(INFO) << "WindowOpenHelper 2.";
214 // TODO(creis): This should open in a new process (i.e., false for the last
215 // argument), but we temporarily avoid swapping processes away from a hosted
216 // app if it has an opener, because some OAuth providers make script calls
217 // between non-app popups and non-app iframes in the app process.
218 // See crbug.com/59285.
219 OpenWindow(tab, base_url.Resolve("path3/empty.html"), true, NULL);
220 LOG(INFO) << "WindowOpenHelper 3.";
222 // Now let's have these pages navigate, into or out of the extension web
223 // extent. They should switch processes.
224 const GURL& app_url(base_url.Resolve("path1/empty.html"));
225 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
226 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
227 non_app_url);
228 LOG(INFO) << "NavigateTabHelper 1.";
229 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(3),
230 app_url);
231 LOG(INFO) << "NavigateTabHelper 2.";
232 EXPECT_NE(tab->GetRenderProcessHost(),
233 browser()->tab_strip_model()->GetWebContentsAt(2)->
234 GetRenderProcessHost());
235 EXPECT_EQ(tab->GetRenderProcessHost(),
236 browser()->tab_strip_model()->GetWebContentsAt(3)->
237 GetRenderProcessHost());
239 // If one of the popup tabs navigates back to the app, window.opener should
240 // be valid.
241 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(6),
242 app_url);
243 LOG(INFO) << "NavigateTabHelper 3.";
244 EXPECT_EQ(tab->GetRenderProcessHost(),
245 browser()->tab_strip_model()->GetWebContentsAt(6)->
246 GetRenderProcessHost());
247 bool windowOpenerValid = false;
248 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
249 browser()->tab_strip_model()->GetWebContentsAt(6),
250 "window.domAutomationController.send(window.opener != null)",
251 &windowOpenerValid));
252 ASSERT_TRUE(windowOpenerValid);
254 LOG(INFO) << "End of test.";
257 // Test that hosted apps without the background permission use a process per app
258 // instance model, such that separate instances are in separate processes.
259 // Flaky on Windows. http://crbug.com/248047
260 #if defined(OS_WIN)
261 #define MAYBE_AppProcessInstances DISABLED_AppProcessInstances
262 #else
263 #define MAYBE_AppProcessInstances AppProcessInstances
264 #endif
265 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessInstances) {
266 TestAppInstancesHelper("app_process_instances");
269 // Test that hosted apps with the background permission but that set
270 // allow_js_access to false also use a process per app instance model.
271 // Separate instances should be in separate processes.
272 // Flaky on XP: http://crbug.com/165834
273 #if defined(OS_WIN)
274 #define MAYBE_AppProcessBackgroundInstances \
275 DISABLED_AppProcessBackgroundInstances
276 #else
277 #define MAYBE_AppProcessBackgroundInstances AppProcessBackgroundInstances
278 #endif
279 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessBackgroundInstances) {
280 TestAppInstancesHelper("app_process_background_instances");
283 // Tests that bookmark apps do not use the app process model and are treated
284 // like normal web pages instead. http://crbug.com/104636.
285 // Timing out on Windows. http://crbug.com/238777
286 #if defined(OS_WIN)
287 #define MAYBE_BookmarkAppGetsNormalProcess DISABLED_BookmarkAppGetsNormalProcess
288 #else
289 #define MAYBE_BookmarkAppGetsNormalProcess BookmarkAppGetsNormalProcess
290 #endif
291 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_BookmarkAppGetsNormalProcess) {
292 ExtensionService* service = extensions::ExtensionSystem::Get(
293 browser()->profile())->extension_service();
294 extensions::ProcessMap* process_map = service->process_map();
296 host_resolver()->AddRule("*", "127.0.0.1");
297 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
298 GURL base_url = GetTestBaseURL("app_process");
300 // Load an app as a bookmark app.
301 std::string error;
302 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
303 test_data_dir_.AppendASCII("app_process"),
304 extensions::Manifest::UNPACKED,
305 Extension::FROM_BOOKMARK,
306 &error));
307 service->OnExtensionInstalled(extension.get(),
308 syncer::StringOrdinal::CreateInitialOrdinal(),
309 false /* no requirement errors */,
310 extensions::Blacklist::NOT_BLACKLISTED,
311 false /* don't wait for idle */);
312 ASSERT_TRUE(extension.get());
313 ASSERT_TRUE(extension->from_bookmark());
315 // Test both opening a URL in a new tab, and opening a tab and then navigating
316 // it. Either way, bookmark app tabs should be considered normal processes
317 // with no elevated privileges and no WebUI bindings.
318 ui_test_utils::NavigateToURLWithDisposition(
319 browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
320 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
321 EXPECT_FALSE(process_map->Contains(
322 browser()->tab_strip_model()->GetWebContentsAt(1)->
323 GetRenderProcessHost()->GetID()));
324 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
326 content::WindowedNotificationObserver tab_added_observer(
327 chrome::NOTIFICATION_TAB_ADDED,
328 content::NotificationService::AllSources());
329 chrome::NewTab(browser());
330 tab_added_observer.Wait();
331 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
332 EXPECT_FALSE(process_map->Contains(
333 browser()->tab_strip_model()->GetWebContentsAt(2)->
334 GetRenderProcessHost()->GetID()));
335 EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
337 // We should have opened 2 new bookmark app tabs. Including the original blank
338 // tab, we now have 3 tabs. Because normal pages use the
339 // process-per-site-instance model, each should be in its own process.
340 ASSERT_EQ(3, browser()->tab_strip_model()->count());
341 WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
342 EXPECT_NE(tab->GetRenderProcessHost(),
343 browser()->tab_strip_model()->GetWebContentsAt(2)->
344 GetRenderProcessHost());
346 // Now let's do the same using window.open. The same should happen.
347 ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
348 browser()->host_desktop_type()));
349 OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
350 OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
352 // Now let's have a tab navigate out of and back into the app's web
353 // extent. Neither navigation should switch processes.
354 const GURL& app_url(base_url.Resolve("path1/empty.html"));
355 const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
356 RenderViewHost* host2 =
357 browser()->tab_strip_model()->GetWebContentsAt(2)->GetRenderViewHost();
358 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
359 non_app_url);
360 EXPECT_EQ(host2->GetProcess(),
361 browser()->tab_strip_model()->GetWebContentsAt(2)->
362 GetRenderProcessHost());
363 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
364 app_url);
365 EXPECT_EQ(host2->GetProcess(),
366 browser()->tab_strip_model()->GetWebContentsAt(2)->
367 GetRenderProcessHost());
370 // Tests that app process switching works properly in the following scenario:
371 // 1. navigate to a page1 in the app
372 // 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
373 // 3. page2 redirects back to a page in the app
374 // The final navigation should end up in the app process.
375 // See http://crbug.com/61757
376 IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
377 host_resolver()->AddRule("*", "127.0.0.1");
378 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
380 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
382 // Open two tabs in the app.
383 GURL base_url = GetTestBaseURL("app_process");
385 chrome::NewTab(browser());
386 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
387 chrome::NewTab(browser());
388 // Wait until the second tab finishes its redirect train (2 hops).
389 // 1. We navigate to redirect.html
390 // 2. Renderer navigates and finishes, counting as a load stop.
391 // 3. Renderer issues the meta refresh to navigate to server-redirect.
392 // 4. Renderer is now in a "provisional load", waiting for navigation to
393 // complete.
394 // 5. Browser sees a redirect response from server-redirect to empty.html, and
395 // transfers that to a new navigation, using RequestTransferURL.
396 // 6. Renderer navigates to empty.html, and finishes loading, counting as the
397 // second load stop
398 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
399 browser(), base_url.Resolve("path1/redirect.html"), 2);
401 // 3 tabs, including the initial about:blank. The last 2 should be the same
402 // process.
403 ASSERT_EQ(3, browser()->tab_strip_model()->count());
404 EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
405 browser()->tab_strip_model()->GetWebContentsAt(2)->
406 GetController().GetLastCommittedEntry()->GetURL().path());
407 EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
408 GetRenderProcessHost(),
409 browser()->tab_strip_model()->GetWebContentsAt(2)->
410 GetRenderProcessHost());
413 // Ensure that re-navigating to a URL after installing or uninstalling it as an
414 // app correctly swaps the tab to the app process. (http://crbug.com/80621)
416 // Fails on Windows. http://crbug.com/238670
417 // Added logging to help diagnose the location of the problem.
418 IN_PROC_BROWSER_TEST_F(AppApiTest, NavigateIntoAppProcess) {
419 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
420 browser()->profile())->extension_service()->process_map();
422 host_resolver()->AddRule("*", "127.0.0.1");
423 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
425 // The app under test acts on URLs whose host is "localhost",
426 // so the URLs we navigate to must have host "localhost".
427 GURL base_url = GetTestBaseURL("app_process");
429 // Load an app URL before loading the app.
430 LOG(INFO) << "Loading path1/empty.html.";
431 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
432 LOG(INFO) << "Loading path1/empty.html - done.";
433 WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
434 EXPECT_FALSE(process_map->Contains(
435 contents->GetRenderProcessHost()->GetID()));
437 // Load app and re-navigate to the page.
438 LOG(INFO) << "Loading extension.";
439 const Extension* app =
440 LoadExtension(test_data_dir_.AppendASCII("app_process"));
441 LOG(INFO) << "Loading extension - done.";
442 ASSERT_TRUE(app);
443 LOG(INFO) << "Loading path1/empty.html.";
444 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
445 LOG(INFO) << "Loading path1/empty.html - done.";
446 EXPECT_TRUE(process_map->Contains(
447 contents->GetRenderProcessHost()->GetID()));
449 // Disable app and re-navigate to the page.
450 LOG(INFO) << "Disabling extension.";
451 DisableExtension(app->id());
452 LOG(INFO) << "Disabling extension - done.";
453 LOG(INFO) << "Loading path1/empty.html.";
454 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
455 LOG(INFO) << "Loading path1/empty.html - done.";
456 EXPECT_FALSE(process_map->Contains(
457 contents->GetRenderProcessHost()->GetID()));
460 // Ensure that reloading a URL after installing or uninstalling it as an app
461 // correctly swaps the tab to the app process. (http://crbug.com/80621)
463 // Added logging to help diagnose the location of the problem.
464 // http://crbug.com/238670
465 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcess) {
466 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
467 browser()->profile())->extension_service()->process_map();
469 host_resolver()->AddRule("*", "127.0.0.1");
470 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
472 // The app under test acts on URLs whose host is "localhost",
473 // so the URLs we navigate to must have host "localhost".
474 GURL base_url = GetTestBaseURL("app_process");
476 // Load app, disable it, and navigate to the page.
477 LOG(INFO) << "Loading extension.";
478 const Extension* app =
479 LoadExtension(test_data_dir_.AppendASCII("app_process"));
480 LOG(INFO) << "Loading extension - done.";
481 ASSERT_TRUE(app);
482 LOG(INFO) << "Disabling extension.";
483 DisableExtension(app->id());
484 LOG(INFO) << "Disabling extension - done.";
485 LOG(INFO) << "Navigate to path1/empty.html.";
486 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
487 LOG(INFO) << "Navigate to path1/empty.html - done.";
488 WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
489 EXPECT_FALSE(process_map->Contains(
490 contents->GetRenderProcessHost()->GetID()));
492 // Enable app and reload the page.
493 LOG(INFO) << "Enabling extension.";
494 EnableExtension(app->id());
495 LOG(INFO) << "Enabling extension - done.";
496 content::WindowedNotificationObserver reload_observer(
497 content::NOTIFICATION_LOAD_STOP,
498 content::Source<NavigationController>(
499 &browser()->tab_strip_model()->GetActiveWebContents()->
500 GetController()));
501 LOG(INFO) << "Reloading.";
502 chrome::Reload(browser(), CURRENT_TAB);
503 reload_observer.Wait();
504 LOG(INFO) << "Reloading - done.";
505 EXPECT_TRUE(process_map->Contains(
506 contents->GetRenderProcessHost()->GetID()));
508 // Disable app and reload the page.
509 LOG(INFO) << "Disabling extension.";
510 DisableExtension(app->id());
511 LOG(INFO) << "Disabling extension - done.";
512 content::WindowedNotificationObserver reload_observer2(
513 content::NOTIFICATION_LOAD_STOP,
514 content::Source<NavigationController>(
515 &browser()->tab_strip_model()->GetActiveWebContents()->
516 GetController()));
517 LOG(INFO) << "Reloading.";
518 chrome::Reload(browser(), CURRENT_TAB);
519 reload_observer2.Wait();
520 LOG(INFO) << "Reloading - done.";
521 EXPECT_FALSE(process_map->Contains(
522 contents->GetRenderProcessHost()->GetID()));
525 // Ensure that reloading a URL with JavaScript after installing or uninstalling
526 // it as an app correctly swaps the process. (http://crbug.com/80621)
528 // Crashes on Windows and Mac. http://crbug.com/238670
529 // Added logging to help diagnose the location of the problem.
530 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcessWithJavaScript) {
531 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
532 browser()->profile())->extension_service()->process_map();
534 host_resolver()->AddRule("*", "127.0.0.1");
535 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
537 // The app under test acts on URLs whose host is "localhost",
538 // so the URLs we navigate to must have host "localhost".
539 GURL base_url = GetTestBaseURL("app_process");
541 // Load app, disable it, and navigate to the page.
542 LOG(INFO) << "Loading extension.";
543 const Extension* app =
544 LoadExtension(test_data_dir_.AppendASCII("app_process"));
545 LOG(INFO) << "Loading extension - done.";
546 ASSERT_TRUE(app);
547 LOG(INFO) << "Disabling extension.";
548 DisableExtension(app->id());
549 LOG(INFO) << "Disabling extension - done.";
550 LOG(INFO) << "Navigate to path1/empty.html.";
551 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
552 LOG(INFO) << "Navigate to path1/empty.html - done.";
553 WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
554 EXPECT_FALSE(process_map->Contains(
555 contents->GetRenderProcessHost()->GetID()));
557 // Enable app and reload via JavaScript.
558 LOG(INFO) << "Enabling extension.";
559 EnableExtension(app->id());
560 LOG(INFO) << "Enabling extension - done.";
561 content::WindowedNotificationObserver js_reload_observer(
562 content::NOTIFICATION_LOAD_STOP,
563 content::Source<NavigationController>(
564 &browser()->tab_strip_model()->GetActiveWebContents()->
565 GetController()));
566 LOG(INFO) << "Executing location.reload().";
567 ASSERT_TRUE(content::ExecuteScript(contents, "location.reload();"));
568 js_reload_observer.Wait();
569 LOG(INFO) << "Executing location.reload() - done.";
570 EXPECT_TRUE(process_map->Contains(
571 contents->GetRenderProcessHost()->GetID()));
573 // Disable app and reload via JavaScript.
574 LOG(INFO) << "Disabling extension.";
575 DisableExtension(app->id());
576 LOG(INFO) << "Disabling extension - done.";
577 content::WindowedNotificationObserver js_reload_observer2(
578 content::NOTIFICATION_LOAD_STOP,
579 content::Source<NavigationController>(
580 &browser()->tab_strip_model()->GetActiveWebContents()->
581 GetController()));
582 LOG(INFO) << "Executing location = location.";
583 ASSERT_TRUE(content::ExecuteScript(contents, "location = location;"));
584 js_reload_observer2.Wait();
585 LOG(INFO) << "Executing location = location - done.";
586 EXPECT_FALSE(process_map->Contains(
587 contents->GetRenderProcessHost()->GetID()));
590 namespace {
592 void RenderViewHostCreated(std::vector<content::RenderViewHost*>* rvh_vector,
593 content::RenderViewHost* rvh) {
594 rvh_vector->push_back(rvh);
597 } // namespace
599 // Tests that if we have a non-app process (path3/container.html) that has an
600 // iframe with a URL in the app's extent (path1/iframe.html), then opening a
601 // link from that iframe to a new window to a URL in the app's extent (path1/
602 // empty.html) results in the new window being in an app process. See
603 // http://crbug.com/89272 for more details.
604 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
605 #if defined(OS_WIN) && defined(USE_ASH)
606 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
607 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
608 return;
609 #endif
611 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
612 browser()->profile())->extension_service()->process_map();
614 host_resolver()->AddRule("*", "127.0.0.1");
615 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
617 GURL base_url = GetTestBaseURL("app_process");
619 // Load app and start URL (not in the app).
620 const Extension* app =
621 LoadExtension(test_data_dir_.AppendASCII("app_process"));
622 ASSERT_TRUE(app);
624 std::vector<content::RenderViewHost*> rvh_vector;
625 content::RenderViewHost::CreatedCallback rvh_callback(
626 base::Bind(&RenderViewHostCreated, &rvh_vector));
627 content::RenderViewHost::AddCreatedCallback(rvh_callback);
628 ui_test_utils::NavigateToURL(browser(),
629 base_url.Resolve("path3/container.html"));
630 content::RenderViewHost::RemoveCreatedCallback(rvh_callback);
631 EXPECT_FALSE(process_map->Contains(
632 browser()->tab_strip_model()->GetWebContentsAt(0)->
633 GetRenderProcessHost()->GetID()));
635 // Popup window should be in the app's process.
636 ASSERT_EQ(3U, rvh_vector.size());
637 RenderViewHost* popup_host = rvh_vector[2];
638 EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
641 // Similar to the previous test, but ensure that popup blocking bypass
642 // isn't granted to the iframe. See crbug.com/117446.
643 #if defined(OS_CHROMEOS)
644 // http://crbug.com/153513
645 #define MAYBE_OpenAppFromIframe DISABLED_OpenAppFromIframe
646 #else
647 #define MAYBE_OpenAppFromIframe OpenAppFromIframe
648 #endif
649 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
650 host_resolver()->AddRule("*", "127.0.0.1");
651 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
653 // Load app and start URL (not in the app).
654 const Extension* app =
655 LoadExtension(test_data_dir_.AppendASCII("app_process"));
656 ASSERT_TRUE(app);
658 ui_test_utils::NavigateToURL(
659 browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
661 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
662 PopupBlockerTabHelper* popup_blocker_tab_helper =
663 PopupBlockerTabHelper::FromWebContents(tab);
664 if (!popup_blocker_tab_helper->GetBlockedPopupsCount()) {
665 content::WindowedNotificationObserver observer(
666 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
667 content::NotificationService::AllSources());
668 observer.Wait();
671 EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
674 // Tests that if an extension launches an app via chrome.tabs.create with an URL
675 // that's not in the app's extent but that server redirects to it, we still end
676 // up with an app process. See http://crbug.com/99349 for more details.
677 IN_PROC_BROWSER_TEST_F(AppApiTest, ServerRedirectToAppFromExtension) {
678 host_resolver()->AddRule("*", "127.0.0.1");
679 ASSERT_TRUE(StartEmbeddedTestServer());
681 LoadExtension(test_data_dir_.AppendASCII("app_process"));
682 const Extension* launcher =
683 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
685 // There should be two navigations by the time the app page is loaded.
686 // 1. The extension launcher page.
687 // 2. The app's URL (which includes a server redirect).
688 // Note that the server redirect does not generate a navigation event.
689 content::TestNavigationObserver test_navigation_observer(
690 browser()->tab_strip_model()->GetActiveWebContents(),
692 test_navigation_observer.StartWatchingNewWebContents();
694 // Load the launcher extension, which should launch the app.
695 ui_test_utils::NavigateToURLWithDisposition(
696 browser(),
697 launcher->GetResourceURL("server_redirect.html"),
698 CURRENT_TAB,
699 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
701 // Wait for app tab to be created and loaded.
702 test_navigation_observer.WaitForObservation(
703 base::Bind(&content::RunMessageLoop),
704 base::Bind(&base::MessageLoop::Quit,
705 base::Unretained(base::MessageLoopForUI::current())));
707 // App has loaded, and chrome.app.isInstalled should be true.
708 bool is_installed = false;
709 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
710 browser()->tab_strip_model()->GetActiveWebContents(),
711 "window.domAutomationController.send(chrome.app.isInstalled)",
712 &is_installed));
713 ASSERT_TRUE(is_installed);
716 // Tests that if an extension launches an app via chrome.tabs.create with an URL
717 // that's not in the app's extent but that client redirects to it, we still end
718 // up with an app process.
719 IN_PROC_BROWSER_TEST_F(AppApiTest, ClientRedirectToAppFromExtension) {
720 host_resolver()->AddRule("*", "127.0.0.1");
721 ASSERT_TRUE(StartEmbeddedTestServer());
723 LoadExtension(test_data_dir_.AppendASCII("app_process"));
724 const Extension* launcher =
725 LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
727 // There should be three navigations by the time the app page is loaded.
728 // 1. The extension launcher page.
729 // 2. The URL that the extension launches, which client redirects.
730 // 3. The app's URL.
731 content::TestNavigationObserver test_navigation_observer(
732 browser()->tab_strip_model()->GetActiveWebContents(),
734 test_navigation_observer.StartWatchingNewWebContents();
736 // Load the launcher extension, which should launch the app.
737 ui_test_utils::NavigateToURLWithDisposition(
738 browser(),
739 launcher->GetResourceURL("client_redirect.html"),
740 CURRENT_TAB,
741 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
743 // Wait for app tab to be created and loaded.
744 test_navigation_observer.WaitForObservation(
745 base::Bind(&content::RunMessageLoop),
746 base::Bind(&base::MessageLoop::Quit,
747 base::Unretained(base::MessageLoopForUI::current())));
749 // App has loaded, and chrome.app.isInstalled should be true.
750 bool is_installed = false;
751 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
752 browser()->tab_strip_model()->GetActiveWebContents(),
753 "window.domAutomationController.send(chrome.app.isInstalled)",
754 &is_installed));
755 ASSERT_TRUE(is_installed);
758 // Tests that if we have an app process (path1/container.html) with a non-app
759 // iframe (path3/iframe.html), then opening a link from that iframe to a new
760 // window to a same-origin non-app URL (path3/empty.html) should keep the window
761 // in the app process.
762 // This is in contrast to OpenAppFromIframe, since here the popup will not be
763 // missing special permissions and should be scriptable from the iframe.
764 // See http://crbug.com/92669 for more details.
765 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
766 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
767 browser()->profile())->extension_service()->process_map();
769 host_resolver()->AddRule("*", "127.0.0.1");
770 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
772 GURL base_url = GetTestBaseURL("app_process");
774 // Load app and start URL (in the app).
775 const Extension* app =
776 LoadExtension(test_data_dir_.AppendASCII("app_process"));
777 ASSERT_TRUE(app);
779 std::vector<content::RenderViewHost*> rvh_vector;
780 content::RenderViewHost::CreatedCallback rvh_callback(
781 base::Bind(&RenderViewHostCreated, &rvh_vector));
782 content::RenderViewHost::AddCreatedCallback(rvh_callback);
783 ui_test_utils::NavigateToURL(browser(),
784 base_url.Resolve("path1/container.html"));
785 content::RenderViewHost::RemoveCreatedCallback(rvh_callback);
786 content::RenderProcessHost* process =
787 browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
788 EXPECT_TRUE(process_map->Contains(process->GetID()));
790 // Popup window should be in the app's process.
791 ASSERT_EQ(2U, rvh_vector.size());
792 RenderViewHost* popup_host = rvh_vector[1];
793 EXPECT_EQ(process, popup_host->GetProcess());
796 // http://crbug.com/118502
797 #if defined(OS_MACOSX) || defined(OS_LINUX)
798 #define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
799 #else
800 #define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
801 #endif
802 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
803 extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
804 browser()->profile())->extension_service()->process_map();
806 host_resolver()->AddRule("*", "127.0.0.1");
807 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
809 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
811 GURL base_url = GetTestBaseURL("app_process");
813 // Load the app, chrome.app.isInstalled should be true.
814 ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
815 WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
816 EXPECT_TRUE(process_map->Contains(
817 contents->GetRenderProcessHost()->GetID()));
818 bool is_installed = false;
819 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
820 contents,
821 "window.domAutomationController.send(chrome.app.isInstalled)",
822 &is_installed));
823 ASSERT_TRUE(is_installed);
825 // Crash the tab and reload it, chrome.app.isInstalled should still be true.
826 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
827 content::WindowedNotificationObserver observer(
828 content::NOTIFICATION_LOAD_STOP,
829 content::Source<NavigationController>(
830 &browser()->tab_strip_model()->GetActiveWebContents()->
831 GetController()));
832 chrome::Reload(browser(), CURRENT_TAB);
833 observer.Wait();
834 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
835 contents,
836 "window.domAutomationController.send(chrome.app.isInstalled)",
837 &is_installed));
838 ASSERT_TRUE(is_installed);