Upstream version 7.36.149.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/process_map.h"
31 #include "extensions/common/extension.h"
32 #include "extensions/common/file_util.h"
33 #include "extensions/common/switches.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "net/test/embedded_test_server/embedded_test_server.h"
36 #include "sync/api/string_ordinal.h"
37
38 using content::NavigationController;
39 using content::RenderViewHost;
40 using content::SiteInstance;
41 using content::WebContents;
42 using extensions::Extension;
43
44 class AppApiTest : public ExtensionApiTest {
45  protected:
46   // Gets the base URL for files for a specific test, making sure that it uses
47   // "localhost" as the hostname, since that is what the extent is declared
48   // as in the test apps manifests.
49   GURL GetTestBaseURL(const std::string& test_directory) {
50     GURL::Replacements replace_host;
51     std::string host_str("localhost");  // must stay in scope with replace_host
52     replace_host.SetHostStr(host_str);
53     GURL base_url = embedded_test_server()->GetURL(
54         "/extensions/api_test/" + test_directory + "/");
55     return base_url.ReplaceComponents(replace_host);
56   }
57
58   // Pass flags to make testing apps easier.
59   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
60     ExtensionApiTest::SetUpCommandLine(command_line);
61     CommandLine::ForCurrentProcess()->AppendSwitch(
62         switches::kDisablePopupBlocking);
63     CommandLine::ForCurrentProcess()->AppendSwitch(
64         extensions::switches::kAllowHTTPBackgroundPage);
65   }
66
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.";
71
72     extensions::ProcessMap* process_map =
73         extensions::ProcessMap::Get(browser()->profile());
74
75     host_resolver()->AddRule("*", "127.0.0.1");
76     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
77
78     ASSERT_TRUE(LoadExtension(
79         test_data_dir_.AppendASCII(app_name)));
80     const Extension* extension = GetSingleLoadedExtension();
81
82     // Open two tabs in the app, one outside it.
83     GURL base_url = GetTestBaseURL(app_name);
84
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());
97
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());
111
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());
120
121     // Opening tabs with window.open should keep the page in the opener's
122     // process.
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());
130   }
131 };
132
133 // Omits the disable-popup-blocking flag so we can cover that case.
134 class BlockedAppApiTest : public AppApiTest {
135  protected:
136   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
137     ExtensionApiTest::SetUpCommandLine(command_line);
138     CommandLine::ForCurrentProcess()->AppendSwitch(
139         extensions::switches::kAllowHTTPBackgroundPage);
140   }
141 };
142
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.";
148
149   extensions::ProcessMap* process_map =
150       extensions::ProcessMap::Get(browser()->profile());
151
152   host_resolver()->AddRule("*", "127.0.0.1");
153   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
154
155   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
156
157   LOG(INFO) << "Loaded extension.";
158
159   // Open two tabs in the app, one outside it.
160   GURL base_url = GetTestBaseURL("app_process");
161
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.";
173
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.";
182
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());
195
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);
202
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());
209
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.";
224
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),
230                      non_app_url);
231   LOG(INFO) << "NavigateTabHelper 1.";
232   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(3),
233                      app_url);
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());
241
242   // If one of the popup tabs navigates back to the app, window.opener should
243   // be valid.
244   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(6),
245                      app_url);
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);
256
257   LOG(INFO) << "End of test.";
258 }
259
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
263 #if defined(OS_WIN)
264 #define MAYBE_AppProcessInstances DISABLED_AppProcessInstances
265 #else
266 #define MAYBE_AppProcessInstances AppProcessInstances
267 #endif
268 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessInstances) {
269   TestAppInstancesHelper("app_process_instances");
270 }
271
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
276 #if defined(OS_WIN)
277 #define MAYBE_AppProcessBackgroundInstances \
278     DISABLED_AppProcessBackgroundInstances
279 #else
280 #define MAYBE_AppProcessBackgroundInstances AppProcessBackgroundInstances
281 #endif
282 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessBackgroundInstances) {
283   TestAppInstancesHelper("app_process_background_instances");
284 }
285
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
289 #if defined(OS_WIN)
290 #define MAYBE_BookmarkAppGetsNormalProcess DISABLED_BookmarkAppGetsNormalProcess
291 #else
292 #define MAYBE_BookmarkAppGetsNormalProcess BookmarkAppGetsNormalProcess
293 #endif
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());
299
300   host_resolver()->AddRule("*", "127.0.0.1");
301   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
302   GURL base_url = GetTestBaseURL("app_process");
303
304   // Load an app as a bookmark app.
305   std::string error;
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,
310       &error));
311   service->OnExtensionInstalled(extension.get(),
312                                 syncer::StringOrdinal::CreateInitialOrdinal(),
313                                 false /* no requirement errors */,
314                                 extensions::NOT_BLACKLISTED,
315                                 false /* don't wait for idle */);
316   ASSERT_TRUE(extension.get());
317   ASSERT_TRUE(extension->from_bookmark());
318
319   // Test both opening a URL in a new tab, and opening a tab and then navigating
320   // it.  Either way, bookmark app tabs should be considered normal processes
321   // with no elevated privileges and no WebUI bindings.
322   ui_test_utils::NavigateToURLWithDisposition(
323       browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
324       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
325   EXPECT_FALSE(process_map->Contains(
326       browser()->tab_strip_model()->GetWebContentsAt(1)->
327           GetRenderProcessHost()->GetID()));
328   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(1)->GetWebUI());
329
330   content::WindowedNotificationObserver tab_added_observer(
331       chrome::NOTIFICATION_TAB_ADDED,
332       content::NotificationService::AllSources());
333   chrome::NewTab(browser());
334   tab_added_observer.Wait();
335   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
336   EXPECT_FALSE(process_map->Contains(
337       browser()->tab_strip_model()->GetWebContentsAt(2)->
338           GetRenderProcessHost()->GetID()));
339   EXPECT_FALSE(browser()->tab_strip_model()->GetWebContentsAt(2)->GetWebUI());
340
341   // We should have opened 2 new bookmark app tabs. Including the original blank
342   // tab, we now have 3 tabs.  Because normal pages use the
343   // process-per-site-instance model, each should be in its own process.
344   ASSERT_EQ(3, browser()->tab_strip_model()->count());
345   WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
346   EXPECT_NE(tab->GetRenderProcessHost(),
347             browser()->tab_strip_model()->GetWebContentsAt(2)->
348                 GetRenderProcessHost());
349
350   // Now let's do the same using window.open. The same should happen.
351   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
352                                         browser()->host_desktop_type()));
353   OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
354   OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
355
356   // Now let's have a tab navigate out of and back into the app's web
357   // extent. Neither navigation should switch processes.
358   const GURL& app_url(base_url.Resolve("path1/empty.html"));
359   const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
360   RenderViewHost* host2 =
361       browser()->tab_strip_model()->GetWebContentsAt(2)->GetRenderViewHost();
362   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
363                      non_app_url);
364   EXPECT_EQ(host2->GetProcess(),
365             browser()->tab_strip_model()->GetWebContentsAt(2)->
366                 GetRenderProcessHost());
367   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
368                      app_url);
369   EXPECT_EQ(host2->GetProcess(),
370             browser()->tab_strip_model()->GetWebContentsAt(2)->
371                 GetRenderProcessHost());
372 }
373
374 // Tests that app process switching works properly in the following scenario:
375 // 1. navigate to a page1 in the app
376 // 2. page1 redirects to a page2 outside the app extent (ie, "/server-redirect")
377 // 3. page2 redirects back to a page in the app
378 // The final navigation should end up in the app process.
379 // See http://crbug.com/61757
380 // Flaky on Linux.  http://crbug.com/341898
381 #if defined(OS_LINUX)
382 #define MAYBE_AppProcessRedirectBack DISABLED_AppProcessRedirectBack
383 #else
384 #define MAYBE_AppProcessRedirectBack AppProcessRedirectBack
385 #endif
386 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessRedirectBack) {
387   host_resolver()->AddRule("*", "127.0.0.1");
388   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
389
390   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
391
392   // Open two tabs in the app.
393   GURL base_url = GetTestBaseURL("app_process");
394
395   chrome::NewTab(browser());
396   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
397   chrome::NewTab(browser());
398   // Wait until the second tab finishes its redirect train (2 hops).
399   // 1. We navigate to redirect.html
400   // 2. Renderer navigates and finishes, counting as a load stop.
401   // 3. Renderer issues the meta refresh to navigate to server-redirect.
402   // 4. Renderer is now in a "provisional load", waiting for navigation to
403   //    complete.
404   // 5. Browser sees a redirect response from server-redirect to empty.html, and
405   //    transfers that to a new navigation, using RequestTransferURL.
406   // 6. Renderer navigates to empty.html, and finishes loading, counting as the
407   //    second load stop
408   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
409       browser(), base_url.Resolve("path1/redirect.html"), 2);
410
411   // 3 tabs, including the initial about:blank. The last 2 should be the same
412   // process.
413   ASSERT_EQ(3, browser()->tab_strip_model()->count());
414   EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
415             browser()->tab_strip_model()->GetWebContentsAt(2)->
416                 GetController().GetLastCommittedEntry()->GetURL().path());
417   EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
418                 GetRenderProcessHost(),
419             browser()->tab_strip_model()->GetWebContentsAt(2)->
420                 GetRenderProcessHost());
421 }
422
423 // Ensure that re-navigating to a URL after installing or uninstalling it as an
424 // app correctly swaps the tab to the app process.  (http://crbug.com/80621)
425 //
426 // Fails on Windows. http://crbug.com/238670
427 // Added logging to help diagnose the location of the problem.
428 IN_PROC_BROWSER_TEST_F(AppApiTest, NavigateIntoAppProcess) {
429   extensions::ProcessMap* process_map =
430       extensions::ProcessMap::Get(browser()->profile());
431
432   host_resolver()->AddRule("*", "127.0.0.1");
433   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
434
435   // The app under test acts on URLs whose host is "localhost",
436   // so the URLs we navigate to must have host "localhost".
437   GURL base_url = GetTestBaseURL("app_process");
438
439   // Load an app URL before loading the app.
440   LOG(INFO) << "Loading path1/empty.html.";
441   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
442   LOG(INFO) << "Loading path1/empty.html - done.";
443   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
444   EXPECT_FALSE(process_map->Contains(
445       contents->GetRenderProcessHost()->GetID()));
446
447   // Load app and re-navigate to the page.
448   LOG(INFO) << "Loading extension.";
449   const Extension* app =
450       LoadExtension(test_data_dir_.AppendASCII("app_process"));
451   LOG(INFO) << "Loading extension - done.";
452   ASSERT_TRUE(app);
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_TRUE(process_map->Contains(
457       contents->GetRenderProcessHost()->GetID()));
458
459   // Disable app and re-navigate to the page.
460   LOG(INFO) << "Disabling extension.";
461   DisableExtension(app->id());
462   LOG(INFO) << "Disabling extension - done.";
463   LOG(INFO) << "Loading path1/empty.html.";
464   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
465   LOG(INFO) << "Loading path1/empty.html - done.";
466   EXPECT_FALSE(process_map->Contains(
467       contents->GetRenderProcessHost()->GetID()));
468 }
469
470 // Ensure that reloading a URL after installing or uninstalling it as an app
471 // correctly swaps the tab to the app process.  (http://crbug.com/80621)
472 //
473 // Added logging to help diagnose the location of the problem.
474 // http://crbug.com/238670
475 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcess) {
476   extensions::ProcessMap* process_map =
477       extensions::ProcessMap::Get(browser()->profile());
478
479   host_resolver()->AddRule("*", "127.0.0.1");
480   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
481
482   // The app under test acts on URLs whose host is "localhost",
483   // so the URLs we navigate to must have host "localhost".
484   GURL base_url = GetTestBaseURL("app_process");
485
486   // Load app, disable it, and navigate to the page.
487   LOG(INFO) << "Loading extension.";
488   const Extension* app =
489       LoadExtension(test_data_dir_.AppendASCII("app_process"));
490   LOG(INFO) << "Loading extension - done.";
491   ASSERT_TRUE(app);
492   LOG(INFO) << "Disabling extension.";
493   DisableExtension(app->id());
494   LOG(INFO) << "Disabling extension - done.";
495   LOG(INFO) << "Navigate to path1/empty.html.";
496   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
497   LOG(INFO) << "Navigate to path1/empty.html - done.";
498   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
499   EXPECT_FALSE(process_map->Contains(
500       contents->GetRenderProcessHost()->GetID()));
501
502   // Enable app and reload the page.
503   LOG(INFO) << "Enabling extension.";
504   EnableExtension(app->id());
505   LOG(INFO) << "Enabling extension - done.";
506   content::WindowedNotificationObserver reload_observer(
507       content::NOTIFICATION_LOAD_STOP,
508       content::Source<NavigationController>(
509           &browser()->tab_strip_model()->GetActiveWebContents()->
510               GetController()));
511   LOG(INFO) << "Reloading.";
512   chrome::Reload(browser(), CURRENT_TAB);
513   reload_observer.Wait();
514   LOG(INFO) << "Reloading - done.";
515   EXPECT_TRUE(process_map->Contains(
516       contents->GetRenderProcessHost()->GetID()));
517
518   // Disable app and reload the page.
519   LOG(INFO) << "Disabling extension.";
520   DisableExtension(app->id());
521   LOG(INFO) << "Disabling extension - done.";
522   content::WindowedNotificationObserver reload_observer2(
523       content::NOTIFICATION_LOAD_STOP,
524       content::Source<NavigationController>(
525           &browser()->tab_strip_model()->GetActiveWebContents()->
526               GetController()));
527   LOG(INFO) << "Reloading.";
528   chrome::Reload(browser(), CURRENT_TAB);
529   reload_observer2.Wait();
530   LOG(INFO) << "Reloading - done.";
531   EXPECT_FALSE(process_map->Contains(
532       contents->GetRenderProcessHost()->GetID()));
533 }
534
535 // Ensure that reloading a URL with JavaScript after installing or uninstalling
536 // it as an app correctly swaps the process.  (http://crbug.com/80621)
537 //
538 // Crashes on Windows and Mac. http://crbug.com/238670
539 // Added logging to help diagnose the location of the problem.
540 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcessWithJavaScript) {
541   extensions::ProcessMap* process_map =
542       extensions::ProcessMap::Get(browser()->profile());
543
544   host_resolver()->AddRule("*", "127.0.0.1");
545   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
546
547   // The app under test acts on URLs whose host is "localhost",
548   // so the URLs we navigate to must have host "localhost".
549   GURL base_url = GetTestBaseURL("app_process");
550
551   // Load app, disable it, and navigate to the page.
552   LOG(INFO) << "Loading extension.";
553   const Extension* app =
554       LoadExtension(test_data_dir_.AppendASCII("app_process"));
555   LOG(INFO) << "Loading extension - done.";
556   ASSERT_TRUE(app);
557   LOG(INFO) << "Disabling extension.";
558   DisableExtension(app->id());
559   LOG(INFO) << "Disabling extension - done.";
560   LOG(INFO) << "Navigate to path1/empty.html.";
561   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
562   LOG(INFO) << "Navigate to path1/empty.html - done.";
563   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
564   EXPECT_FALSE(process_map->Contains(
565       contents->GetRenderProcessHost()->GetID()));
566
567   // Enable app and reload via JavaScript.
568   LOG(INFO) << "Enabling extension.";
569   EnableExtension(app->id());
570   LOG(INFO) << "Enabling extension - done.";
571   content::WindowedNotificationObserver js_reload_observer(
572       content::NOTIFICATION_LOAD_STOP,
573       content::Source<NavigationController>(
574           &browser()->tab_strip_model()->GetActiveWebContents()->
575               GetController()));
576   LOG(INFO) << "Executing location.reload().";
577   ASSERT_TRUE(content::ExecuteScript(contents, "location.reload();"));
578   js_reload_observer.Wait();
579   LOG(INFO) << "Executing location.reload() - done.";
580   EXPECT_TRUE(process_map->Contains(
581       contents->GetRenderProcessHost()->GetID()));
582
583   // Disable app and reload via JavaScript.
584   LOG(INFO) << "Disabling extension.";
585   DisableExtension(app->id());
586   LOG(INFO) << "Disabling extension - done.";
587   content::WindowedNotificationObserver js_reload_observer2(
588       content::NOTIFICATION_LOAD_STOP,
589       content::Source<NavigationController>(
590           &browser()->tab_strip_model()->GetActiveWebContents()->
591               GetController()));
592   LOG(INFO) << "Executing location = location.";
593   ASSERT_TRUE(content::ExecuteScript(contents, "location = location;"));
594   js_reload_observer2.Wait();
595   LOG(INFO) << "Executing location = location - done.";
596   EXPECT_FALSE(process_map->Contains(
597       contents->GetRenderProcessHost()->GetID()));
598 }
599
600 // Tests that if we have a non-app process (path3/container.html) that has an
601 // iframe with  a URL in the app's extent (path1/iframe.html), then opening a
602 // link from that iframe to a new window to a URL in the app's extent (path1/
603 // empty.html) results in the new window being in an app process. See
604 // http://crbug.com/89272 for more details.
605 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
606 #if defined(OS_WIN) && defined(USE_ASH)
607   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
608   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
609     return;
610 #endif
611
612   extensions::ProcessMap* process_map =
613       extensions::ProcessMap::Get(browser()->profile());
614
615   host_resolver()->AddRule("*", "127.0.0.1");
616   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
617
618   GURL base_url = GetTestBaseURL("app_process");
619
620   // Load app and start URL (not in the app).
621   const Extension* app =
622       LoadExtension(test_data_dir_.AppendASCII("app_process"));
623   ASSERT_TRUE(app);
624
625   ui_test_utils::NavigateToURL(browser(),
626                                base_url.Resolve("path3/container.html"));
627   EXPECT_FALSE(process_map->Contains(
628       browser()->tab_strip_model()->GetWebContentsAt(0)->
629           GetRenderProcessHost()->GetID()));
630
631   const BrowserList* active_browser_list =
632       BrowserList::GetInstance(chrome::GetActiveDesktop());
633   EXPECT_EQ(2U, active_browser_list->size());
634   content::WebContents* popup_contents =
635       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
636   content::WaitForLoadStop(popup_contents);
637
638   // Popup window should be in the app's process.
639   RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
640   EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
641 }
642
643 // Similar to the previous test, but ensure that popup blocking bypass
644 // isn't granted to the iframe.  See crbug.com/117446.
645 #if defined(OS_CHROMEOS)
646 // http://crbug.com/153513
647 #define MAYBE_OpenAppFromIframe DISABLED_OpenAppFromIframe
648 #else
649 #define MAYBE_OpenAppFromIframe OpenAppFromIframe
650 #endif
651 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
652   host_resolver()->AddRule("*", "127.0.0.1");
653   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
654
655   // Load app and start URL (not in the app).
656   const Extension* app =
657       LoadExtension(test_data_dir_.AppendASCII("app_process"));
658   ASSERT_TRUE(app);
659
660   ui_test_utils::NavigateToURL(
661       browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
662
663   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
664   PopupBlockerTabHelper* popup_blocker_tab_helper =
665       PopupBlockerTabHelper::FromWebContents(tab);
666   if (!popup_blocker_tab_helper->GetBlockedPopupsCount()) {
667     content::WindowedNotificationObserver observer(
668         chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
669         content::NotificationService::AllSources());
670     observer.Wait();
671   }
672
673   EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
674 }
675
676 // Tests that if an extension launches an app via chrome.tabs.create with an URL
677 // that's not in the app's extent but that server redirects to it, we still end
678 // up with an app process. See http://crbug.com/99349 for more details.
679 IN_PROC_BROWSER_TEST_F(AppApiTest, ServerRedirectToAppFromExtension) {
680   host_resolver()->AddRule("*", "127.0.0.1");
681   ASSERT_TRUE(StartEmbeddedTestServer());
682
683   LoadExtension(test_data_dir_.AppendASCII("app_process"));
684   const Extension* launcher =
685       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
686
687   // There should be two navigations by the time the app page is loaded.
688   // 1. The extension launcher page.
689   // 2. The app's URL (which includes a server redirect).
690   // Note that the server redirect does not generate a navigation event.
691   content::TestNavigationObserver test_navigation_observer(
692       browser()->tab_strip_model()->GetActiveWebContents(),
693       2);
694   test_navigation_observer.StartWatchingNewWebContents();
695
696   // Load the launcher extension, which should launch the app.
697   ui_test_utils::NavigateToURLWithDisposition(
698       browser(),
699       launcher->GetResourceURL("server_redirect.html"),
700       CURRENT_TAB,
701       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
702
703   // Wait for app tab to be created and loaded.
704   test_navigation_observer.Wait();
705
706   // App has loaded, and chrome.app.isInstalled should be true.
707   bool is_installed = false;
708   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
709       browser()->tab_strip_model()->GetActiveWebContents(),
710       "window.domAutomationController.send(chrome.app.isInstalled)",
711       &is_installed));
712   ASSERT_TRUE(is_installed);
713 }
714
715 // Tests that if an extension launches an app via chrome.tabs.create with an URL
716 // that's not in the app's extent but that client redirects to it, we still end
717 // up with an app process.
718 IN_PROC_BROWSER_TEST_F(AppApiTest, ClientRedirectToAppFromExtension) {
719   host_resolver()->AddRule("*", "127.0.0.1");
720   ASSERT_TRUE(StartEmbeddedTestServer());
721
722   LoadExtension(test_data_dir_.AppendASCII("app_process"));
723   const Extension* launcher =
724       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
725
726   // There should be three navigations by the time the app page is loaded.
727   // 1. The extension launcher page.
728   // 2. The URL that the extension launches, which client redirects.
729   // 3. The app's URL.
730   content::TestNavigationObserver test_navigation_observer(
731       browser()->tab_strip_model()->GetActiveWebContents(),
732       3);
733   test_navigation_observer.StartWatchingNewWebContents();
734
735   // Load the launcher extension, which should launch the app.
736   ui_test_utils::NavigateToURLWithDisposition(
737       browser(),
738       launcher->GetResourceURL("client_redirect.html"),
739       CURRENT_TAB,
740       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
741
742   // Wait for app tab to be created and loaded.
743   test_navigation_observer.Wait();
744
745   // App has loaded, and chrome.app.isInstalled should be true.
746   bool is_installed = false;
747   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
748       browser()->tab_strip_model()->GetActiveWebContents(),
749       "window.domAutomationController.send(chrome.app.isInstalled)",
750       &is_installed));
751   ASSERT_TRUE(is_installed);
752 }
753
754 // Tests that if we have an app process (path1/container.html) with a non-app
755 // iframe (path3/iframe.html), then opening a link from that iframe to a new
756 // window to a same-origin non-app URL (path3/empty.html) should keep the window
757 // in the app process.
758 // This is in contrast to OpenAppFromIframe, since here the popup will not be
759 // missing special permissions and should be scriptable from the iframe.
760 // See http://crbug.com/92669 for more details.
761 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
762   extensions::ProcessMap* process_map =
763       extensions::ProcessMap::Get(browser()->profile());
764
765   host_resolver()->AddRule("*", "127.0.0.1");
766   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
767
768   GURL base_url = GetTestBaseURL("app_process");
769
770   // Load app and start URL (in the app).
771   const Extension* app =
772       LoadExtension(test_data_dir_.AppendASCII("app_process"));
773   ASSERT_TRUE(app);
774
775   ui_test_utils::NavigateToURL(browser(),
776                                base_url.Resolve("path1/container.html"));
777   content::RenderProcessHost* process =
778       browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
779   EXPECT_TRUE(process_map->Contains(process->GetID()));
780
781   // Popup window should be in the app's process.
782   const BrowserList* active_browser_list =
783       BrowserList::GetInstance(chrome::GetActiveDesktop());
784   EXPECT_EQ(2U, active_browser_list->size());
785   content::WebContents* popup_contents =
786       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
787   content::WaitForLoadStop(popup_contents);
788
789   RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
790   EXPECT_EQ(process, popup_host->GetProcess());
791 }
792
793 // http://crbug.com/118502
794 #if defined(OS_MACOSX) || defined(OS_LINUX)
795 #define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
796 #else
797 #define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
798 #endif
799 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
800   extensions::ProcessMap* process_map =
801       extensions::ProcessMap::Get(browser()->profile());
802
803   host_resolver()->AddRule("*", "127.0.0.1");
804   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
805
806   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
807
808   GURL base_url = GetTestBaseURL("app_process");
809
810   // Load the app, chrome.app.isInstalled should be true.
811   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
812   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
813   EXPECT_TRUE(process_map->Contains(
814       contents->GetRenderProcessHost()->GetID()));
815   bool is_installed = false;
816   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
817       contents,
818       "window.domAutomationController.send(chrome.app.isInstalled)",
819       &is_installed));
820   ASSERT_TRUE(is_installed);
821
822   // Crash the tab and reload it, chrome.app.isInstalled should still be true.
823   content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
824   content::WindowedNotificationObserver observer(
825       content::NOTIFICATION_LOAD_STOP,
826       content::Source<NavigationController>(
827           &browser()->tab_strip_model()->GetActiveWebContents()->
828               GetController()));
829   chrome::Reload(browser(), CURRENT_TAB);
830   observer.Wait();
831   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
832       contents,
833       "window.domAutomationController.send(chrome.app.isInstalled)",
834       &is_installed));
835   ASSERT_TRUE(is_installed);
836 }
837
838 // Test that a cross-process navigation away from a hosted app stays in the same
839 // BrowsingInstance, so that postMessage calls to the app's other windows still
840 // work.
841 IN_PROC_BROWSER_TEST_F(AppApiTest, SameBrowsingInstanceAfterSwap) {
842   extensions::ProcessMap* process_map =
843       extensions::ProcessMap::Get(browser()->profile());
844
845   host_resolver()->AddRule("*", "127.0.0.1");
846   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
847
848   GURL base_url = GetTestBaseURL("app_process");
849
850   // Load app and start URL (in the app).
851   const Extension* app =
852       LoadExtension(test_data_dir_.AppendASCII("app_process"));
853   ASSERT_TRUE(app);
854
855   ui_test_utils::NavigateToURL(browser(),
856                                base_url.Resolve("path1/iframe.html"));
857   content::SiteInstance* app_instance =
858       browser()->tab_strip_model()->GetWebContentsAt(0)->GetSiteInstance();
859   EXPECT_TRUE(process_map->Contains(app_instance->GetProcess()->GetID()));
860
861   // Popup window should be in the app's process.
862   const BrowserList* active_browser_list =
863       BrowserList::GetInstance(chrome::GetActiveDesktop());
864   EXPECT_EQ(2U, active_browser_list->size());
865   content::WebContents* popup_contents =
866       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
867   content::WaitForLoadStop(popup_contents);
868
869   SiteInstance* popup_instance = popup_contents->GetSiteInstance();
870   EXPECT_EQ(app_instance, popup_instance);
871
872   // Navigate the popup to another process outside the app.
873   GURL non_app_url(base_url.Resolve("path3/empty.html"));
874   ui_test_utils::NavigateToURL(active_browser_list->get(1), non_app_url);
875   SiteInstance* new_instance = popup_contents->GetSiteInstance();
876   EXPECT_NE(app_instance, new_instance);
877
878   // It should still be in the same BrowsingInstance, allowing postMessage to
879   // work.
880   EXPECT_TRUE(app_instance->IsRelatedSiteInstance(new_instance));
881 }