Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / app_process_apitest.cc
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.
4
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"
38
39 using content::NavigationController;
40 using content::RenderViewHost;
41 using content::SiteInstance;
42 using content::WebContents;
43 using extensions::Extension;
44
45 class AppApiTest : public ExtensionApiTest {
46  protected:
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     std::string host_str("localhost");  // must stay in scope with replace_host
53     replace_host.SetHostStr(host_str);
54     GURL base_url = embedded_test_server()->GetURL(
55         "/extensions/api_test/" + test_directory + "/");
56     return base_url.ReplaceComponents(replace_host);
57   }
58
59   // Pass flags to make testing apps easier.
60   void SetUpCommandLine(CommandLine* command_line) override {
61     ExtensionApiTest::SetUpCommandLine(command_line);
62     CommandLine::ForCurrentProcess()->AppendSwitch(
63         switches::kDisablePopupBlocking);
64     CommandLine::ForCurrentProcess()->AppendSwitch(
65         extensions::switches::kAllowHTTPBackgroundPage);
66   }
67
68   // Helper function to test that independent tabs of the named app are loaded
69   // into separate processes.
70   void TestAppInstancesHelper(const std::string& app_name) {
71     LOG(INFO) << "Start of test.";
72
73     extensions::ProcessMap* process_map =
74         extensions::ProcessMap::Get(browser()->profile());
75
76     host_resolver()->AddRule("*", "127.0.0.1");
77     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
78
79     ASSERT_TRUE(LoadExtension(
80         test_data_dir_.AppendASCII(app_name)));
81     const Extension* extension = GetSingleLoadedExtension();
82
83     // Open two tabs in the app, one outside it.
84     GURL base_url = GetTestBaseURL(app_name);
85
86     // Test both opening a URL in a new tab, and opening a tab and then
87     // navigating it.  Either way, app tabs should be considered extension
88     // processes, but they have no elevated privileges and thus should not
89     // have WebUI bindings.
90     ui_test_utils::NavigateToURLWithDisposition(
91         browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
92         ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
93     LOG(INFO) << "Nav 1.";
94     EXPECT_TRUE(process_map->Contains(
95         browser()->tab_strip_model()->GetWebContentsAt(1)->
96             GetRenderProcessHost()->GetID()));
97     EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
98
99     content::WindowedNotificationObserver tab_added_observer(
100         chrome::NOTIFICATION_TAB_ADDED,
101         content::NotificationService::AllSources());
102     chrome::NewTab(browser());
103     tab_added_observer.Wait();
104     LOG(INFO) << "New tab.";
105     ui_test_utils::NavigateToURL(browser(),
106                                  base_url.Resolve("path2/empty.html"));
107     LOG(INFO) << "Nav 2.";
108     EXPECT_TRUE(process_map->Contains(
109         browser()->tab_strip_model()->GetWebContentsAt(2)->
110             GetRenderProcessHost()->GetID()));
111     EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
112
113     // We should have opened 2 new extension tabs. Including the original blank
114     // tab, we now have 3 tabs. The two app tabs should not be in the same
115     // process, since they do not have the background permission.  (Thus, we
116     // want to separate them to improve responsiveness.)
117     ASSERT_EQ(3, browser()->tab_strip_model()->count());
118     WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(1);
119     WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(2);
120     EXPECT_NE(tab1->GetRenderProcessHost(), tab2->GetRenderProcessHost());
121
122     // Opening tabs with window.open should keep the page in the opener's
123     // process.
124     ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
125                                           browser()->host_desktop_type()));
126     OpenWindow(tab1, base_url.Resolve("path1/empty.html"), true, NULL);
127     LOG(INFO) << "WindowOpenHelper 1.";
128     OpenWindow(tab2, base_url.Resolve("path2/empty.html"), true, NULL);
129     LOG(INFO) << "End of test.";
130     UnloadExtension(extension->id());
131   }
132 };
133
134 // Omits the disable-popup-blocking flag so we can cover that case.
135 class BlockedAppApiTest : public AppApiTest {
136  protected:
137   void SetUpCommandLine(CommandLine* command_line) override {
138     ExtensionApiTest::SetUpCommandLine(command_line);
139     CommandLine::ForCurrentProcess()->AppendSwitch(
140         extensions::switches::kAllowHTTPBackgroundPage);
141   }
142 };
143
144 // Tests that hosted apps with the background permission get a process-per-app
145 // model, since all pages need to be able to script the background page.
146 // http://crbug.com/172750
147 IN_PROC_BROWSER_TEST_F(AppApiTest, DISABLED_AppProcess) {
148   LOG(INFO) << "Start of test.";
149
150   extensions::ProcessMap* process_map =
151       extensions::ProcessMap::Get(browser()->profile());
152
153   host_resolver()->AddRule("*", "127.0.0.1");
154   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
155
156   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
157
158   LOG(INFO) << "Loaded extension.";
159
160   // Open two tabs in the app, one outside it.
161   GURL base_url = GetTestBaseURL("app_process");
162
163   // Test both opening a URL in a new tab, and opening a tab and then navigating
164   // it.  Either way, app tabs should be considered extension processes, but
165   // they have no elevated privileges and thus should not have WebUI bindings.
166   ui_test_utils::NavigateToURLWithDisposition(
167       browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
168       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
169   EXPECT_TRUE(process_map->Contains(
170       browser()->tab_strip_model()->GetWebContentsAt(1)->
171           GetRenderProcessHost()->GetID()));
172   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
173   LOG(INFO) << "Nav 1.";
174
175   ui_test_utils::NavigateToURLWithDisposition(
176       browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
177       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
178   EXPECT_TRUE(process_map->Contains(
179       browser()->tab_strip_model()->GetWebContentsAt(2)->
180           GetRenderProcessHost()->GetID()));
181   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
182   LOG(INFO) << "Nav 2.";
183
184   content::WindowedNotificationObserver tab_added_observer(
185       chrome::NOTIFICATION_TAB_ADDED,
186       content::NotificationService::AllSources());
187   chrome::NewTab(browser());
188   tab_added_observer.Wait();
189   LOG(INFO) << "New tab.";
190   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
191   LOG(INFO) << "Nav 3.";
192   EXPECT_FALSE(process_map->Contains(
193       browser()->tab_strip_model()->GetWebContentsAt(3)->
194           GetRenderProcessHost()->GetID()));
195   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(3)->GetWebUI());
196
197   // We should have opened 3 new extension tabs. Including the original blank
198   // tab, we now have 4 tabs. Because the app_process app has the background
199   // permission, all of its instances are in the same process.  Thus two tabs
200   // should be part of the extension app and grouped in the same process.
201   ASSERT_EQ(4, browser()->tab_strip_model()->count());
202   WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
203
204   EXPECT_EQ(tab->GetRenderProcessHost(),
205             browser()->tab_strip_model()->GetWebContentsAt(2)->
206                 GetRenderProcessHost());
207   EXPECT_NE(tab->GetRenderProcessHost(),
208             browser()->tab_strip_model()->GetWebContentsAt(3)->
209                 GetRenderProcessHost());
210
211   // Now let's do the same using window.open. The same should happen.
212   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
213                                         browser()->host_desktop_type()));
214   OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
215   LOG(INFO) << "WindowOpenHelper 1.";
216   OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
217   LOG(INFO) << "WindowOpenHelper 2.";
218   // TODO(creis): This should open in a new process (i.e., false for the last
219   // argument), but we temporarily avoid swapping processes away from a hosted
220   // app if it has an opener, because some OAuth providers make script calls
221   // between non-app popups and non-app iframes in the app process.
222   // See crbug.com/59285.
223   OpenWindow(tab, base_url.Resolve("path3/empty.html"), true, NULL);
224   LOG(INFO) << "WindowOpenHelper 3.";
225
226   // Now let's have these pages navigate, into or out of the extension web
227   // extent. They should switch processes.
228   const GURL& app_url(base_url.Resolve("path1/empty.html"));
229   const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
230   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
231                      non_app_url);
232   LOG(INFO) << "NavigateTabHelper 1.";
233   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(3),
234                      app_url);
235   LOG(INFO) << "NavigateTabHelper 2.";
236   EXPECT_NE(tab->GetRenderProcessHost(),
237             browser()->tab_strip_model()->GetWebContentsAt(2)->
238                 GetRenderProcessHost());
239   EXPECT_EQ(tab->GetRenderProcessHost(),
240             browser()->tab_strip_model()->GetWebContentsAt(3)->
241                 GetRenderProcessHost());
242
243   // If one of the popup tabs navigates back to the app, window.opener should
244   // be valid.
245   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(6),
246                      app_url);
247   LOG(INFO) << "NavigateTabHelper 3.";
248   EXPECT_EQ(tab->GetRenderProcessHost(),
249             browser()->tab_strip_model()->GetWebContentsAt(6)->
250                 GetRenderProcessHost());
251   bool windowOpenerValid = false;
252   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
253       browser()->tab_strip_model()->GetWebContentsAt(6),
254       "window.domAutomationController.send(window.opener != null)",
255       &windowOpenerValid));
256   ASSERT_TRUE(windowOpenerValid);
257
258   LOG(INFO) << "End of test.";
259 }
260
261 // Test that hosted apps without the background permission use a process per app
262 // instance model, such that separate instances are in separate processes.
263 // Flaky on Windows. http://crbug.com/248047
264 #if defined(OS_WIN)
265 #define MAYBE_AppProcessInstances DISABLED_AppProcessInstances
266 #else
267 #define MAYBE_AppProcessInstances AppProcessInstances
268 #endif
269 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessInstances) {
270   TestAppInstancesHelper("app_process_instances");
271 }
272
273 // Test that hosted apps with the background permission but that set
274 // allow_js_access to false also use a process per app instance model.
275 // Separate instances should be in separate processes.
276 // Flaky on XP: http://crbug.com/165834
277 #if defined(OS_WIN)
278 #define MAYBE_AppProcessBackgroundInstances \
279     DISABLED_AppProcessBackgroundInstances
280 #else
281 #define MAYBE_AppProcessBackgroundInstances AppProcessBackgroundInstances
282 #endif
283 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessBackgroundInstances) {
284   TestAppInstancesHelper("app_process_background_instances");
285 }
286
287 // Tests that bookmark apps do not use the app process model and are treated
288 // like normal web pages instead.  http://crbug.com/104636.
289 // Timing out on Windows. http://crbug.com/238777
290 #if defined(OS_WIN)
291 #define MAYBE_BookmarkAppGetsNormalProcess DISABLED_BookmarkAppGetsNormalProcess
292 #else
293 #define MAYBE_BookmarkAppGetsNormalProcess BookmarkAppGetsNormalProcess
294 #endif
295 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_BookmarkAppGetsNormalProcess) {
296   ExtensionService* service = extensions::ExtensionSystem::Get(
297       browser()->profile())->extension_service();
298   extensions::ProcessMap* process_map =
299       extensions::ProcessMap::Get(browser()->profile());
300
301   host_resolver()->AddRule("*", "127.0.0.1");
302   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
303   GURL base_url = GetTestBaseURL("app_process");
304
305   // Load an app as a bookmark app.
306   std::string error;
307   scoped_refptr<const Extension> extension(extensions::file_util::LoadExtension(
308       test_data_dir_.AppendASCII("app_process"),
309       extensions::Manifest::UNPACKED,
310       Extension::FROM_BOOKMARK,
311       &error));
312   service->OnExtensionInstalled(extension.get(),
313                                 syncer::StringOrdinal::CreateInitialOrdinal(),
314                                 extensions::kInstallFlagInstallImmediately);
315   ASSERT_TRUE(extension.get());
316   ASSERT_TRUE(extension->from_bookmark());
317
318   // Test both opening a URL in a new tab, and opening a tab and then navigating
319   // it.  Either way, bookmark app tabs should be considered normal processes
320   // with no elevated privileges and no WebUI bindings.
321   ui_test_utils::NavigateToURLWithDisposition(
322       browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
323       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
324   EXPECT_FALSE(process_map->Contains(
325       browser()->tab_strip_model()->GetWebContentsAt(1)->
326           GetRenderProcessHost()->GetID()));
327   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
328
329   content::WindowedNotificationObserver tab_added_observer(
330       chrome::NOTIFICATION_TAB_ADDED,
331       content::NotificationService::AllSources());
332   chrome::NewTab(browser());
333   tab_added_observer.Wait();
334   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
335   EXPECT_FALSE(process_map->Contains(
336       browser()->tab_strip_model()->GetWebContentsAt(2)->
337           GetRenderProcessHost()->GetID()));
338   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
339
340   // We should have opened 2 new bookmark app tabs. Including the original blank
341   // tab, we now have 3 tabs.  Because normal pages use the
342   // process-per-site-instance model, each should be in its own process.
343   ASSERT_EQ(3, browser()->tab_strip_model()->count());
344   WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
345   EXPECT_NE(tab->GetRenderProcessHost(),
346             browser()->tab_strip_model()->GetWebContentsAt(2)->
347                 GetRenderProcessHost());
348
349   // Now let's do the same using window.open. The same should happen.
350   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
351                                         browser()->host_desktop_type()));
352   OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
353   OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
354
355   // Now let's have a tab navigate out of and back into the app's web
356   // extent. Neither navigation should switch processes.
357   const GURL& app_url(base_url.Resolve("path1/empty.html"));
358   const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
359   RenderViewHost* host2 =
360       browser()->tab_strip_model()->GetWebContentsAt(2)->GetRenderViewHost();
361   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
362                      non_app_url);
363   EXPECT_EQ(host2->GetProcess(),
364             browser()->tab_strip_model()->GetWebContentsAt(2)->
365                 GetRenderProcessHost());
366   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
367                      app_url);
368   EXPECT_EQ(host2->GetProcess(),
369             browser()->tab_strip_model()->GetWebContentsAt(2)->
370                 GetRenderProcessHost());
371 }
372
373 // Tests that app process switching works properly in the following scenario:
374 // 1. navigate to a page1 in the app
375 // 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
376 // 3. page2 redirects back to a page in the app
377 // The final navigation should end up in the app process.
378 // See http://crbug.com/61757
379 // Flaky.  http://crbug.com/341898
380 IN_PROC_BROWSER_TEST_F(AppApiTest, DISABLED_AppProcessRedirectBack) {
381   host_resolver()->AddRule("*", "127.0.0.1");
382   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
383
384   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
385
386   // Open two tabs in the app.
387   GURL base_url = GetTestBaseURL("app_process");
388
389   chrome::NewTab(browser());
390   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
391   chrome::NewTab(browser());
392   // Wait until the second tab finishes its redirect train (2 hops).
393   // 1. We navigate to redirect.html
394   // 2. Renderer navigates and finishes, counting as a load stop.
395   // 3. Renderer issues the meta refresh to navigate to server-redirect.
396   // 4. Renderer is now in a "provisional load", waiting for navigation to
397   //    complete.
398   // 5. Browser sees a redirect response from server-redirect to empty.html, and
399   //    transfers that to a new navigation, using RequestTransferURL.
400   // 6. Renderer navigates to empty.html, and finishes loading, counting as the
401   //    second load stop
402   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
403       browser(), base_url.Resolve("path1/redirect.html"), 2);
404
405   // 3 tabs, including the initial about:blank. The last 2 should be the same
406   // process.
407   ASSERT_EQ(3, browser()->tab_strip_model()->count());
408   EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
409             browser()->tab_strip_model()->GetWebContentsAt(2)->
410                 GetController().GetLastCommittedEntry()->GetURL().path());
411   EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
412                 GetRenderProcessHost(),
413             browser()->tab_strip_model()->GetWebContentsAt(2)->
414                 GetRenderProcessHost());
415 }
416
417 // Ensure that re-navigating to a URL after installing or uninstalling it as an
418 // app correctly swaps the tab to the app process.  (http://crbug.com/80621)
419 //
420 // Fails on Windows. http://crbug.com/238670
421 // Added logging to help diagnose the location of the problem.
422 IN_PROC_BROWSER_TEST_F(AppApiTest, NavigateIntoAppProcess) {
423   extensions::ProcessMap* process_map =
424       extensions::ProcessMap::Get(browser()->profile());
425
426   host_resolver()->AddRule("*", "127.0.0.1");
427   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
428
429   // The app under test acts on URLs whose host is "localhost",
430   // so the URLs we navigate to must have host "localhost".
431   GURL base_url = GetTestBaseURL("app_process");
432
433   // Load an app URL before loading the app.
434   LOG(INFO) << "Loading path1/empty.html.";
435   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
436   LOG(INFO) << "Loading path1/empty.html - done.";
437   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
438   EXPECT_FALSE(process_map->Contains(
439       contents->GetRenderProcessHost()->GetID()));
440
441   // Load app and re-navigate to the page.
442   LOG(INFO) << "Loading extension.";
443   const Extension* app =
444       LoadExtension(test_data_dir_.AppendASCII("app_process"));
445   LOG(INFO) << "Loading extension - done.";
446   ASSERT_TRUE(app);
447   LOG(INFO) << "Loading path1/empty.html.";
448   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
449   LOG(INFO) << "Loading path1/empty.html - done.";
450   EXPECT_TRUE(process_map->Contains(
451       contents->GetRenderProcessHost()->GetID()));
452
453   // Disable app and re-navigate to the page.
454   LOG(INFO) << "Disabling extension.";
455   DisableExtension(app->id());
456   LOG(INFO) << "Disabling extension - done.";
457   LOG(INFO) << "Loading path1/empty.html.";
458   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
459   LOG(INFO) << "Loading path1/empty.html - done.";
460   EXPECT_FALSE(process_map->Contains(
461       contents->GetRenderProcessHost()->GetID()));
462 }
463
464 // Ensure that reloading a URL after installing or uninstalling it as an app
465 // correctly swaps the tab to the app process.  (http://crbug.com/80621)
466 //
467 // Added logging to help diagnose the location of the problem.
468 // http://crbug.com/238670
469 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcess) {
470   extensions::ProcessMap* process_map =
471       extensions::ProcessMap::Get(browser()->profile());
472
473   host_resolver()->AddRule("*", "127.0.0.1");
474   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
475
476   // The app under test acts on URLs whose host is "localhost",
477   // so the URLs we navigate to must have host "localhost".
478   GURL base_url = GetTestBaseURL("app_process");
479
480   // Load app, disable it, and navigate to the page.
481   LOG(INFO) << "Loading extension.";
482   const Extension* app =
483       LoadExtension(test_data_dir_.AppendASCII("app_process"));
484   LOG(INFO) << "Loading extension - done.";
485   ASSERT_TRUE(app);
486   LOG(INFO) << "Disabling extension.";
487   DisableExtension(app->id());
488   LOG(INFO) << "Disabling extension - done.";
489   LOG(INFO) << "Navigate to path1/empty.html.";
490   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
491   LOG(INFO) << "Navigate to path1/empty.html - done.";
492   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
493   EXPECT_FALSE(process_map->Contains(
494       contents->GetRenderProcessHost()->GetID()));
495
496   // Enable app and reload the page.
497   LOG(INFO) << "Enabling extension.";
498   EnableExtension(app->id());
499   LOG(INFO) << "Enabling extension - done.";
500   content::WindowedNotificationObserver reload_observer(
501       content::NOTIFICATION_LOAD_STOP,
502       content::Source<NavigationController>(
503           &browser()->tab_strip_model()->GetActiveWebContents()->
504               GetController()));
505   LOG(INFO) << "Reloading.";
506   chrome::Reload(browser(), CURRENT_TAB);
507   reload_observer.Wait();
508   LOG(INFO) << "Reloading - done.";
509   EXPECT_TRUE(process_map->Contains(
510       contents->GetRenderProcessHost()->GetID()));
511
512   // Disable app and reload the page.
513   LOG(INFO) << "Disabling extension.";
514   DisableExtension(app->id());
515   LOG(INFO) << "Disabling extension - done.";
516   content::WindowedNotificationObserver reload_observer2(
517       content::NOTIFICATION_LOAD_STOP,
518       content::Source<NavigationController>(
519           &browser()->tab_strip_model()->GetActiveWebContents()->
520               GetController()));
521   LOG(INFO) << "Reloading.";
522   chrome::Reload(browser(), CURRENT_TAB);
523   reload_observer2.Wait();
524   LOG(INFO) << "Reloading - done.";
525   EXPECT_FALSE(process_map->Contains(
526       contents->GetRenderProcessHost()->GetID()));
527 }
528
529 // Ensure that reloading a URL with JavaScript after installing or uninstalling
530 // it as an app correctly swaps the process.  (http://crbug.com/80621)
531 //
532 // Crashes on Windows and Mac. http://crbug.com/238670
533 // Added logging to help diagnose the location of the problem.
534 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcessWithJavaScript) {
535   extensions::ProcessMap* process_map =
536       extensions::ProcessMap::Get(browser()->profile());
537
538   host_resolver()->AddRule("*", "127.0.0.1");
539   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
540
541   // The app under test acts on URLs whose host is "localhost",
542   // so the URLs we navigate to must have host "localhost".
543   GURL base_url = GetTestBaseURL("app_process");
544
545   // Load app, disable it, and navigate to the page.
546   LOG(INFO) << "Loading extension.";
547   const Extension* app =
548       LoadExtension(test_data_dir_.AppendASCII("app_process"));
549   LOG(INFO) << "Loading extension - done.";
550   ASSERT_TRUE(app);
551   LOG(INFO) << "Disabling extension.";
552   DisableExtension(app->id());
553   LOG(INFO) << "Disabling extension - done.";
554   LOG(INFO) << "Navigate to path1/empty.html.";
555   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
556   LOG(INFO) << "Navigate to path1/empty.html - done.";
557   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
558   EXPECT_FALSE(process_map->Contains(
559       contents->GetRenderProcessHost()->GetID()));
560
561   // Enable app and reload via JavaScript.
562   LOG(INFO) << "Enabling extension.";
563   EnableExtension(app->id());
564   LOG(INFO) << "Enabling extension - done.";
565   content::WindowedNotificationObserver js_reload_observer(
566       content::NOTIFICATION_LOAD_STOP,
567       content::Source<NavigationController>(
568           &browser()->tab_strip_model()->GetActiveWebContents()->
569               GetController()));
570   LOG(INFO) << "Executing location.reload().";
571   ASSERT_TRUE(content::ExecuteScript(contents, "location.reload();"));
572   js_reload_observer.Wait();
573   LOG(INFO) << "Executing location.reload() - done.";
574   EXPECT_TRUE(process_map->Contains(
575       contents->GetRenderProcessHost()->GetID()));
576
577   // Disable app and reload via JavaScript.
578   LOG(INFO) << "Disabling extension.";
579   DisableExtension(app->id());
580   LOG(INFO) << "Disabling extension - done.";
581   content::WindowedNotificationObserver js_reload_observer2(
582       content::NOTIFICATION_LOAD_STOP,
583       content::Source<NavigationController>(
584           &browser()->tab_strip_model()->GetActiveWebContents()->
585               GetController()));
586   LOG(INFO) << "Executing location = location.";
587   ASSERT_TRUE(content::ExecuteScript(contents, "location = location;"));
588   js_reload_observer2.Wait();
589   LOG(INFO) << "Executing location = location - done.";
590   EXPECT_FALSE(process_map->Contains(
591       contents->GetRenderProcessHost()->GetID()));
592 }
593
594 // Tests that if we have a non-app process (path3/container.html) that has an
595 // iframe with  a URL in the app's extent (path1/iframe.html), then opening a
596 // link from that iframe to a new window to a URL in the app's extent (path1/
597 // empty.html) results in the new window being in an app process. See
598 // http://crbug.com/89272 for more details.
599 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
600 #if defined(OS_WIN) && defined(USE_ASH)
601   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
602   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
603     return;
604 #endif
605
606   extensions::ProcessMap* process_map =
607       extensions::ProcessMap::Get(browser()->profile());
608
609   host_resolver()->AddRule("*", "127.0.0.1");
610   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
611
612   GURL base_url = GetTestBaseURL("app_process");
613
614   // Load app and start URL (not in the app).
615   const Extension* app =
616       LoadExtension(test_data_dir_.AppendASCII("app_process"));
617   ASSERT_TRUE(app);
618
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()));
624
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);
631
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()));
635 }
636
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
642 #else
643 #define MAYBE_OpenAppFromIframe OpenAppFromIframe
644 #endif
645 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
646   host_resolver()->AddRule("*", "127.0.0.1");
647   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
648
649   // Load app and start URL (not in the app).
650   const Extension* app =
651       LoadExtension(test_data_dir_.AppendASCII("app_process"));
652   ASSERT_TRUE(app);
653
654   ui_test_utils::NavigateToURL(
655       browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
656
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());
664     observer.Wait();
665   }
666
667   EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
668 }
669
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());
676
677   LoadExtension(test_data_dir_.AppendASCII("app_process"));
678   const Extension* launcher =
679       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
680
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(),
687       2);
688   test_navigation_observer.StartWatchingNewWebContents();
689
690   // Load the launcher extension, which should launch the app.
691   ui_test_utils::NavigateToURLWithDisposition(
692       browser(),
693       launcher->GetResourceURL("server_redirect.html"),
694       CURRENT_TAB,
695       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
696
697   // Wait for app tab to be created and loaded.
698   test_navigation_observer.Wait();
699
700   // App has loaded, and chrome.app.isInstalled should be true.
701   bool is_installed = false;
702   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
703       browser()->tab_strip_model()->GetActiveWebContents(),
704       "window.domAutomationController.send(chrome.app.isInstalled)",
705       &is_installed));
706   ASSERT_TRUE(is_installed);
707 }
708
709 // Tests that if an extension launches an app via chrome.tabs.create with an URL
710 // that's not in the app's extent but that client redirects to it, we still end
711 // up with an app process.
712 IN_PROC_BROWSER_TEST_F(AppApiTest, ClientRedirectToAppFromExtension) {
713   host_resolver()->AddRule("*", "127.0.0.1");
714   ASSERT_TRUE(StartEmbeddedTestServer());
715
716   LoadExtension(test_data_dir_.AppendASCII("app_process"));
717   const Extension* launcher =
718       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
719
720   // There should be three navigations by the time the app page is loaded.
721   // 1. The extension launcher page.
722   // 2. The URL that the extension launches, which client redirects.
723   // 3. The app's URL.
724   content::TestNavigationObserver test_navigation_observer(
725       browser()->tab_strip_model()->GetActiveWebContents(),
726       3);
727   test_navigation_observer.StartWatchingNewWebContents();
728
729   // Load the launcher extension, which should launch the app.
730   ui_test_utils::NavigateToURLWithDisposition(
731       browser(),
732       launcher->GetResourceURL("client_redirect.html"),
733       CURRENT_TAB,
734       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
735
736   // Wait for app tab to be created and loaded.
737   test_navigation_observer.Wait();
738
739   // App has loaded, and chrome.app.isInstalled should be true.
740   bool is_installed = false;
741   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
742       browser()->tab_strip_model()->GetActiveWebContents(),
743       "window.domAutomationController.send(chrome.app.isInstalled)",
744       &is_installed));
745   ASSERT_TRUE(is_installed);
746 }
747
748 // Tests that if we have an app process (path1/container.html) with a non-app
749 // iframe (path3/iframe.html), then opening a link from that iframe to a new
750 // window to a same-origin non-app URL (path3/empty.html) should keep the window
751 // in the app process.
752 // This is in contrast to OpenAppFromIframe, since here the popup will not be
753 // missing special permissions and should be scriptable from the iframe.
754 // See http://crbug.com/92669 for more details.
755 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
756   extensions::ProcessMap* process_map =
757       extensions::ProcessMap::Get(browser()->profile());
758
759   host_resolver()->AddRule("*", "127.0.0.1");
760   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
761
762   GURL base_url = GetTestBaseURL("app_process");
763
764   // Load app and start URL (in the app).
765   const Extension* app =
766       LoadExtension(test_data_dir_.AppendASCII("app_process"));
767   ASSERT_TRUE(app);
768
769   ui_test_utils::NavigateToURL(browser(),
770                                base_url.Resolve("path1/container.html"));
771   content::RenderProcessHost* process =
772       browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
773   EXPECT_TRUE(process_map->Contains(process->GetID()));
774
775   // Popup window should be in the app's process.
776   const BrowserList* active_browser_list =
777       BrowserList::GetInstance(chrome::GetActiveDesktop());
778   EXPECT_EQ(2U, active_browser_list->size());
779   content::WebContents* popup_contents =
780       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
781   content::WaitForLoadStop(popup_contents);
782
783   RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
784   EXPECT_EQ(process, popup_host->GetProcess());
785 }
786
787 // http://crbug.com/118502
788 #if defined(OS_MACOSX) || defined(OS_LINUX)
789 #define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
790 #else
791 #define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
792 #endif
793 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
794   extensions::ProcessMap* process_map =
795       extensions::ProcessMap::Get(browser()->profile());
796
797   host_resolver()->AddRule("*", "127.0.0.1");
798   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
799
800   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
801
802   GURL base_url = GetTestBaseURL("app_process");
803
804   // Load the app, chrome.app.isInstalled should be true.
805   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
806   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
807   EXPECT_TRUE(process_map->Contains(
808       contents->GetRenderProcessHost()->GetID()));
809   bool is_installed = false;
810   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
811       contents,
812       "window.domAutomationController.send(chrome.app.isInstalled)",
813       &is_installed));
814   ASSERT_TRUE(is_installed);
815
816   // Crash the tab and reload it, chrome.app.isInstalled should still be true.
817   content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
818   content::WindowedNotificationObserver observer(
819       content::NOTIFICATION_LOAD_STOP,
820       content::Source<NavigationController>(
821           &browser()->tab_strip_model()->GetActiveWebContents()->
822               GetController()));
823   chrome::Reload(browser(), CURRENT_TAB);
824   observer.Wait();
825   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
826       contents,
827       "window.domAutomationController.send(chrome.app.isInstalled)",
828       &is_installed));
829   ASSERT_TRUE(is_installed);
830 }
831
832 // Test that a cross-process navigation away from a hosted app stays in the same
833 // BrowsingInstance, so that postMessage calls to the app's other windows still
834 // work.
835 IN_PROC_BROWSER_TEST_F(AppApiTest, SameBrowsingInstanceAfterSwap) {
836   extensions::ProcessMap* process_map =
837       extensions::ProcessMap::Get(browser()->profile());
838
839   host_resolver()->AddRule("*", "127.0.0.1");
840   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
841
842   GURL base_url = GetTestBaseURL("app_process");
843
844   // Load app and start URL (in the app).
845   const Extension* app =
846       LoadExtension(test_data_dir_.AppendASCII("app_process"));
847   ASSERT_TRUE(app);
848
849   ui_test_utils::NavigateToURL(browser(),
850                                base_url.Resolve("path1/iframe.html"));
851   content::SiteInstance* app_instance =
852       browser()->tab_strip_model()->GetWebContentsAt(0)->GetSiteInstance();
853   EXPECT_TRUE(process_map->Contains(app_instance->GetProcess()->GetID()));
854
855   // Popup window should be in the app's process.
856   const BrowserList* active_browser_list =
857       BrowserList::GetInstance(chrome::GetActiveDesktop());
858   EXPECT_EQ(2U, active_browser_list->size());
859   content::WebContents* popup_contents =
860       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
861   content::WaitForLoadStop(popup_contents);
862
863   SiteInstance* popup_instance = popup_contents->GetSiteInstance();
864   EXPECT_EQ(app_instance, popup_instance);
865
866   // Navigate the popup to another process outside the app.
867   GURL non_app_url(base_url.Resolve("path3/empty.html"));
868   ui_test_utils::NavigateToURL(active_browser_list->get(1), non_app_url);
869   SiteInstance* new_instance = popup_contents->GetSiteInstance();
870   EXPECT_NE(app_instance, new_instance);
871
872   // It should still be in the same BrowsingInstance, allowing postMessage to
873   // work.
874   EXPECT_TRUE(app_instance->IsRelatedSiteInstance(new_instance));
875 }