Home | History | Annotate | Download | only in extensions
      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_host.h"
      9 #include "chrome/browser/extensions/extension_service.h"
     10 #include "chrome/browser/extensions/extension_system.h"
     11 #include "chrome/browser/profiles/profile.h"
     12 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/browser_commands.h"
     15 #include "chrome/browser/ui/browser_finder.h"
     16 #include "chrome/browser/ui/browser_list.h"
     17 #include "chrome/browser/ui/browser_window.h"
     18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     19 #include "chrome/common/chrome_switches.h"
     20 #include "chrome/common/extensions/extension_file_util.h"
     21 #include "chrome/test/base/test_switches.h"
     22 #include "chrome/test/base/ui_test_utils.h"
     23 #include "content/public/browser/navigation_entry.h"
     24 #include "content/public/browser/notification_service.h"
     25 #include "content/public/browser/render_process_host.h"
     26 #include "content/public/browser/render_view_host.h"
     27 #include "content/public/browser/site_instance.h"
     28 #include "content/public/browser/web_contents.h"
     29 #include "content/public/test/browser_test_utils.h"
     30 #include "content/public/test/test_navigation_observer.h"
     31 #include "extensions/browser/process_map.h"
     32 #include "extensions/common/extension.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(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(std::string app_name) {
     70     LOG(INFO) << "Start of test.";
     71 
     72     extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
     73         browser()->profile())->extension_service()->process_map();
     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 = extensions::ExtensionSystem::Get(
    150       browser()->profile())->extension_service()->process_map();
    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 = service->process_map();
    298 
    299   host_resolver()->AddRule("*", "127.0.0.1");
    300   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    301   GURL base_url = GetTestBaseURL("app_process");
    302 
    303   // Load an app as a bookmark app.
    304   std::string error;
    305   scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
    306       test_data_dir_.AppendASCII("app_process"),
    307       extensions::Manifest::UNPACKED,
    308       Extension::FROM_BOOKMARK,
    309       &error));
    310   service->OnExtensionInstalled(extension.get(),
    311                                 syncer::StringOrdinal::CreateInitialOrdinal(),
    312                                 false /* no requirement errors */,
    313                                 extensions::Blacklist::NOT_BLACKLISTED,
    314                                 false /* don't wait for idle */);
    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 IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
    380   host_resolver()->AddRule("*", "127.0.0.1");
    381   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    382 
    383   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
    384 
    385   // Open two tabs in the app.
    386   GURL base_url = GetTestBaseURL("app_process");
    387 
    388   chrome::NewTab(browser());
    389   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    390   chrome::NewTab(browser());
    391   // Wait until the second tab finishes its redirect train (2 hops).
    392   // 1. We navigate to redirect.html
    393   // 2. Renderer navigates and finishes, counting as a load stop.
    394   // 3. Renderer issues the meta refresh to navigate to server-redirect.
    395   // 4. Renderer is now in a "provisional load", waiting for navigation to
    396   //    complete.
    397   // 5. Browser sees a redirect response from server-redirect to empty.html, and
    398   //    transfers that to a new navigation, using RequestTransferURL.
    399   // 6. Renderer navigates to empty.html, and finishes loading, counting as the
    400   //    second load stop
    401   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
    402       browser(), base_url.Resolve("path1/redirect.html"), 2);
    403 
    404   // 3 tabs, including the initial about:blank. The last 2 should be the same
    405   // process.
    406   ASSERT_EQ(3, browser()->tab_strip_model()->count());
    407   EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
    408             browser()->tab_strip_model()->GetWebContentsAt(2)->
    409                 GetController().GetLastCommittedEntry()->GetURL().path());
    410   EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
    411                 GetRenderProcessHost(),
    412             browser()->tab_strip_model()->GetWebContentsAt(2)->
    413                 GetRenderProcessHost());
    414 }
    415 
    416 // Ensure that re-navigating to a URL after installing or uninstalling it as an
    417 // app correctly swaps the tab to the app process.  (http://crbug.com/80621)
    418 //
    419 // Fails on Windows. http://crbug.com/238670
    420 // Added logging to help diagnose the location of the problem.
    421 IN_PROC_BROWSER_TEST_F(AppApiTest, NavigateIntoAppProcess) {
    422   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    423       browser()->profile())->extension_service()->process_map();
    424 
    425   host_resolver()->AddRule("*", "127.0.0.1");
    426   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    427 
    428   // The app under test acts on URLs whose host is "localhost",
    429   // so the URLs we navigate to must have host "localhost".
    430   GURL base_url = GetTestBaseURL("app_process");
    431 
    432   // Load an app URL before loading the app.
    433   LOG(INFO) << "Loading path1/empty.html.";
    434   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    435   LOG(INFO) << "Loading path1/empty.html - done.";
    436   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
    437   EXPECT_FALSE(process_map->Contains(
    438       contents->GetRenderProcessHost()->GetID()));
    439 
    440   // Load app and re-navigate to the page.
    441   LOG(INFO) << "Loading extension.";
    442   const Extension* app =
    443       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    444   LOG(INFO) << "Loading extension - done.";
    445   ASSERT_TRUE(app);
    446   LOG(INFO) << "Loading path1/empty.html.";
    447   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    448   LOG(INFO) << "Loading path1/empty.html - done.";
    449   EXPECT_TRUE(process_map->Contains(
    450       contents->GetRenderProcessHost()->GetID()));
    451 
    452   // Disable app and re-navigate to the page.
    453   LOG(INFO) << "Disabling extension.";
    454   DisableExtension(app->id());
    455   LOG(INFO) << "Disabling extension - done.";
    456   LOG(INFO) << "Loading path1/empty.html.";
    457   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    458   LOG(INFO) << "Loading path1/empty.html - done.";
    459   EXPECT_FALSE(process_map->Contains(
    460       contents->GetRenderProcessHost()->GetID()));
    461 }
    462 
    463 // Ensure that reloading a URL after installing or uninstalling it as an app
    464 // correctly swaps the tab to the app process.  (http://crbug.com/80621)
    465 //
    466 // Added logging to help diagnose the location of the problem.
    467 // http://crbug.com/238670
    468 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcess) {
    469   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    470       browser()->profile())->extension_service()->process_map();
    471 
    472   host_resolver()->AddRule("*", "127.0.0.1");
    473   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    474 
    475   // The app under test acts on URLs whose host is "localhost",
    476   // so the URLs we navigate to must have host "localhost".
    477   GURL base_url = GetTestBaseURL("app_process");
    478 
    479   // Load app, disable it, and navigate to the page.
    480   LOG(INFO) << "Loading extension.";
    481   const Extension* app =
    482       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    483   LOG(INFO) << "Loading extension - done.";
    484   ASSERT_TRUE(app);
    485   LOG(INFO) << "Disabling extension.";
    486   DisableExtension(app->id());
    487   LOG(INFO) << "Disabling extension - done.";
    488   LOG(INFO) << "Navigate to path1/empty.html.";
    489   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    490   LOG(INFO) << "Navigate to path1/empty.html - done.";
    491   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
    492   EXPECT_FALSE(process_map->Contains(
    493       contents->GetRenderProcessHost()->GetID()));
    494 
    495   // Enable app and reload the page.
    496   LOG(INFO) << "Enabling extension.";
    497   EnableExtension(app->id());
    498   LOG(INFO) << "Enabling extension - done.";
    499   content::WindowedNotificationObserver reload_observer(
    500       content::NOTIFICATION_LOAD_STOP,
    501       content::Source<NavigationController>(
    502           &browser()->tab_strip_model()->GetActiveWebContents()->
    503               GetController()));
    504   LOG(INFO) << "Reloading.";
    505   chrome::Reload(browser(), CURRENT_TAB);
    506   reload_observer.Wait();
    507   LOG(INFO) << "Reloading - done.";
    508   EXPECT_TRUE(process_map->Contains(
    509       contents->GetRenderProcessHost()->GetID()));
    510 
    511   // Disable app and reload the page.
    512   LOG(INFO) << "Disabling extension.";
    513   DisableExtension(app->id());
    514   LOG(INFO) << "Disabling extension - done.";
    515   content::WindowedNotificationObserver reload_observer2(
    516       content::NOTIFICATION_LOAD_STOP,
    517       content::Source<NavigationController>(
    518           &browser()->tab_strip_model()->GetActiveWebContents()->
    519               GetController()));
    520   LOG(INFO) << "Reloading.";
    521   chrome::Reload(browser(), CURRENT_TAB);
    522   reload_observer2.Wait();
    523   LOG(INFO) << "Reloading - done.";
    524   EXPECT_FALSE(process_map->Contains(
    525       contents->GetRenderProcessHost()->GetID()));
    526 }
    527 
    528 // Ensure that reloading a URL with JavaScript after installing or uninstalling
    529 // it as an app correctly swaps the process.  (http://crbug.com/80621)
    530 //
    531 // Crashes on Windows and Mac. http://crbug.com/238670
    532 // Added logging to help diagnose the location of the problem.
    533 IN_PROC_BROWSER_TEST_F(AppApiTest, ReloadIntoAppProcessWithJavaScript) {
    534   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    535       browser()->profile())->extension_service()->process_map();
    536 
    537   host_resolver()->AddRule("*", "127.0.0.1");
    538   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    539 
    540   // The app under test acts on URLs whose host is "localhost",
    541   // so the URLs we navigate to must have host "localhost".
    542   GURL base_url = GetTestBaseURL("app_process");
    543 
    544   // Load app, disable it, and navigate to the page.
    545   LOG(INFO) << "Loading extension.";
    546   const Extension* app =
    547       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    548   LOG(INFO) << "Loading extension - done.";
    549   ASSERT_TRUE(app);
    550   LOG(INFO) << "Disabling extension.";
    551   DisableExtension(app->id());
    552   LOG(INFO) << "Disabling extension - done.";
    553   LOG(INFO) << "Navigate to path1/empty.html.";
    554   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    555   LOG(INFO) << "Navigate to path1/empty.html - done.";
    556   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
    557   EXPECT_FALSE(process_map->Contains(
    558       contents->GetRenderProcessHost()->GetID()));
    559 
    560   // Enable app and reload via JavaScript.
    561   LOG(INFO) << "Enabling extension.";
    562   EnableExtension(app->id());
    563   LOG(INFO) << "Enabling extension - done.";
    564   content::WindowedNotificationObserver js_reload_observer(
    565       content::NOTIFICATION_LOAD_STOP,
    566       content::Source<NavigationController>(
    567           &browser()->tab_strip_model()->GetActiveWebContents()->
    568               GetController()));
    569   LOG(INFO) << "Executing location.reload().";
    570   ASSERT_TRUE(content::ExecuteScript(contents, "location.reload();"));
    571   js_reload_observer.Wait();
    572   LOG(INFO) << "Executing location.reload() - done.";
    573   EXPECT_TRUE(process_map->Contains(
    574       contents->GetRenderProcessHost()->GetID()));
    575 
    576   // Disable app and reload via JavaScript.
    577   LOG(INFO) << "Disabling extension.";
    578   DisableExtension(app->id());
    579   LOG(INFO) << "Disabling extension - done.";
    580   content::WindowedNotificationObserver js_reload_observer2(
    581       content::NOTIFICATION_LOAD_STOP,
    582       content::Source<NavigationController>(
    583           &browser()->tab_strip_model()->GetActiveWebContents()->
    584               GetController()));
    585   LOG(INFO) << "Executing location = location.";
    586   ASSERT_TRUE(content::ExecuteScript(contents, "location = location;"));
    587   js_reload_observer2.Wait();
    588   LOG(INFO) << "Executing location = location - done.";
    589   EXPECT_FALSE(process_map->Contains(
    590       contents->GetRenderProcessHost()->GetID()));
    591 }
    592 
    593 // Tests that if we have a non-app process (path3/container.html) that has an
    594 // iframe with  a URL in the app's extent (path1/iframe.html), then opening a
    595 // link from that iframe to a new window to a URL in the app's extent (path1/
    596 // empty.html) results in the new window being in an app process. See
    597 // http://crbug.com/89272 for more details.
    598 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
    599 #if defined(OS_WIN) && defined(USE_ASH)
    600   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    601   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    602     return;
    603 #endif
    604 
    605   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    606       browser()->profile())->extension_service()->process_map();
    607 
    608   host_resolver()->AddRule("*", "127.0.0.1");
    609   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    610 
    611   GURL base_url = GetTestBaseURL("app_process");
    612 
    613   // Load app and start URL (not in the app).
    614   const Extension* app =
    615       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    616   ASSERT_TRUE(app);
    617 
    618   ui_test_utils::NavigateToURL(browser(),
    619                                base_url.Resolve("path3/container.html"));
    620   EXPECT_FALSE(process_map->Contains(
    621       browser()->tab_strip_model()->GetWebContentsAt(0)->
    622           GetRenderProcessHost()->GetID()));
    623 
    624   const BrowserList* active_browser_list =
    625       BrowserList::GetInstance(chrome::GetActiveDesktop());
    626   EXPECT_EQ(2U, active_browser_list->size());
    627   content::WebContents* popup_contents =
    628       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
    629   content::WaitForLoadStop(popup_contents);
    630 
    631   // Popup window should be in the app's process.
    632   RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
    633   EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
    634 }
    635 
    636 // Similar to the previous test, but ensure that popup blocking bypass
    637 // isn't granted to the iframe.  See crbug.com/117446.
    638 #if defined(OS_CHROMEOS)
    639 // http://crbug.com/153513
    640 #define MAYBE_OpenAppFromIframe DISABLED_OpenAppFromIframe
    641 #else
    642 #define MAYBE_OpenAppFromIframe OpenAppFromIframe
    643 #endif
    644 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
    645   host_resolver()->AddRule("*", "127.0.0.1");
    646   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    647 
    648   // Load app and start URL (not in the app).
    649   const Extension* app =
    650       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    651   ASSERT_TRUE(app);
    652 
    653   ui_test_utils::NavigateToURL(
    654       browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
    655 
    656   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
    657   PopupBlockerTabHelper* popup_blocker_tab_helper =
    658       PopupBlockerTabHelper::FromWebContents(tab);
    659   if (!popup_blocker_tab_helper->GetBlockedPopupsCount()) {
    660     content::WindowedNotificationObserver observer(
    661         chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
    662         content::NotificationService::AllSources());
    663     observer.Wait();
    664   }
    665 
    666   EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
    667 }
    668 
    669 // Tests that if an extension launches an app via chrome.tabs.create with an URL
    670 // that's not in the app's extent but that server redirects to it, we still end
    671 // up with an app process. See http://crbug.com/99349 for more details.
    672 IN_PROC_BROWSER_TEST_F(AppApiTest, ServerRedirectToAppFromExtension) {
    673   host_resolver()->AddRule("*", "127.0.0.1");
    674   ASSERT_TRUE(StartEmbeddedTestServer());
    675 
    676   LoadExtension(test_data_dir_.AppendASCII("app_process"));
    677   const Extension* launcher =
    678       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
    679 
    680   // There should be two navigations by the time the app page is loaded.
    681   // 1. The extension launcher page.
    682   // 2. The app's URL (which includes a server redirect).
    683   // Note that the server redirect does not generate a navigation event.
    684   content::TestNavigationObserver test_navigation_observer(
    685       browser()->tab_strip_model()->GetActiveWebContents(),
    686       2);
    687   test_navigation_observer.StartWatchingNewWebContents();
    688 
    689   // Load the launcher extension, which should launch the app.
    690   ui_test_utils::NavigateToURLWithDisposition(
    691       browser(),
    692       launcher->GetResourceURL("server_redirect.html"),
    693       CURRENT_TAB,
    694       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    695 
    696   // Wait for app tab to be created and loaded.
    697   test_navigation_observer.Wait();
    698 
    699   // App has loaded, and chrome.app.isInstalled should be true.
    700   bool is_installed = false;
    701   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    702       browser()->tab_strip_model()->GetActiveWebContents(),
    703       "window.domAutomationController.send(chrome.app.isInstalled)",
    704       &is_installed));
    705   ASSERT_TRUE(is_installed);
    706 }
    707 
    708 // Tests that if an extension launches an app via chrome.tabs.create with an URL
    709 // that's not in the app's extent but that client redirects to it, we still end
    710 // up with an app process.
    711 IN_PROC_BROWSER_TEST_F(AppApiTest, ClientRedirectToAppFromExtension) {
    712   host_resolver()->AddRule("*", "127.0.0.1");
    713   ASSERT_TRUE(StartEmbeddedTestServer());
    714 
    715   LoadExtension(test_data_dir_.AppendASCII("app_process"));
    716   const Extension* launcher =
    717       LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
    718 
    719   // There should be three navigations by the time the app page is loaded.
    720   // 1. The extension launcher page.
    721   // 2. The URL that the extension launches, which client redirects.
    722   // 3. The app's URL.
    723   content::TestNavigationObserver test_navigation_observer(
    724       browser()->tab_strip_model()->GetActiveWebContents(),
    725       3);
    726   test_navigation_observer.StartWatchingNewWebContents();
    727 
    728   // Load the launcher extension, which should launch the app.
    729   ui_test_utils::NavigateToURLWithDisposition(
    730       browser(),
    731       launcher->GetResourceURL("client_redirect.html"),
    732       CURRENT_TAB,
    733       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    734 
    735   // Wait for app tab to be created and loaded.
    736   test_navigation_observer.Wait();
    737 
    738   // App has loaded, and chrome.app.isInstalled should be true.
    739   bool is_installed = false;
    740   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    741       browser()->tab_strip_model()->GetActiveWebContents(),
    742       "window.domAutomationController.send(chrome.app.isInstalled)",
    743       &is_installed));
    744   ASSERT_TRUE(is_installed);
    745 }
    746 
    747 // Tests that if we have an app process (path1/container.html) with a non-app
    748 // iframe (path3/iframe.html), then opening a link from that iframe to a new
    749 // window to a same-origin non-app URL (path3/empty.html) should keep the window
    750 // in the app process.
    751 // This is in contrast to OpenAppFromIframe, since here the popup will not be
    752 // missing special permissions and should be scriptable from the iframe.
    753 // See http://crbug.com/92669 for more details.
    754 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
    755   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    756       browser()->profile())->extension_service()->process_map();
    757 
    758   host_resolver()->AddRule("*", "127.0.0.1");
    759   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    760 
    761   GURL base_url = GetTestBaseURL("app_process");
    762 
    763   // Load app and start URL (in the app).
    764   const Extension* app =
    765       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    766   ASSERT_TRUE(app);
    767 
    768   ui_test_utils::NavigateToURL(browser(),
    769                                base_url.Resolve("path1/container.html"));
    770   content::RenderProcessHost* process =
    771       browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
    772   EXPECT_TRUE(process_map->Contains(process->GetID()));
    773 
    774   // Popup window should be in the app's process.
    775   const BrowserList* active_browser_list =
    776       BrowserList::GetInstance(chrome::GetActiveDesktop());
    777   EXPECT_EQ(2U, active_browser_list->size());
    778   content::WebContents* popup_contents =
    779       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
    780   content::WaitForLoadStop(popup_contents);
    781 
    782   RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
    783   EXPECT_EQ(process, popup_host->GetProcess());
    784 }
    785 
    786 // http://crbug.com/118502
    787 #if defined(OS_MACOSX) || defined(OS_LINUX)
    788 #define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
    789 #else
    790 #define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
    791 #endif
    792 IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
    793   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    794       browser()->profile())->extension_service()->process_map();
    795 
    796   host_resolver()->AddRule("*", "127.0.0.1");
    797   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    798 
    799   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
    800 
    801   GURL base_url = GetTestBaseURL("app_process");
    802 
    803   // Load the app, chrome.app.isInstalled should be true.
    804   ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
    805   WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
    806   EXPECT_TRUE(process_map->Contains(
    807       contents->GetRenderProcessHost()->GetID()));
    808   bool is_installed = false;
    809   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    810       contents,
    811       "window.domAutomationController.send(chrome.app.isInstalled)",
    812       &is_installed));
    813   ASSERT_TRUE(is_installed);
    814 
    815   // Crash the tab and reload it, chrome.app.isInstalled should still be true.
    816   content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
    817   content::WindowedNotificationObserver observer(
    818       content::NOTIFICATION_LOAD_STOP,
    819       content::Source<NavigationController>(
    820           &browser()->tab_strip_model()->GetActiveWebContents()->
    821               GetController()));
    822   chrome::Reload(browser(), CURRENT_TAB);
    823   observer.Wait();
    824   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    825       contents,
    826       "window.domAutomationController.send(chrome.app.isInstalled)",
    827       &is_installed));
    828   ASSERT_TRUE(is_installed);
    829 }
    830 
    831 // Test that a cross-process navigation away from a hosted app stays in the same
    832 // BrowsingInstance, so that postMessage calls to the app's other windows still
    833 // work.
    834 IN_PROC_BROWSER_TEST_F(AppApiTest, SameBrowsingInstanceAfterSwap) {
    835   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
    836       browser()->profile())->extension_service()->process_map();
    837 
    838   host_resolver()->AddRule("*", "127.0.0.1");
    839   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    840 
    841   GURL base_url = GetTestBaseURL("app_process");
    842 
    843   // Load app and start URL (in the app).
    844   const Extension* app =
    845       LoadExtension(test_data_dir_.AppendASCII("app_process"));
    846   ASSERT_TRUE(app);
    847 
    848   ui_test_utils::NavigateToURL(browser(),
    849                                base_url.Resolve("path1/iframe.html"));
    850   content::SiteInstance* app_instance =
    851       browser()->tab_strip_model()->GetWebContentsAt(0)->GetSiteInstance();
    852   EXPECT_TRUE(process_map->Contains(app_instance->GetProcess()->GetID()));
    853 
    854   // Popup window should be in the app's process.
    855   const BrowserList* active_browser_list =
    856       BrowserList::GetInstance(chrome::GetActiveDesktop());
    857   EXPECT_EQ(2U, active_browser_list->size());
    858   content::WebContents* popup_contents =
    859       active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
    860   content::WaitForLoadStop(popup_contents);
    861 
    862   SiteInstance* popup_instance = popup_contents->GetSiteInstance();
    863   EXPECT_EQ(app_instance, popup_instance);
    864 
    865   // Navigate the popup to another process outside the app.
    866   GURL non_app_url(base_url.Resolve("path3/empty.html"));
    867   ui_test_utils::NavigateToURL(active_browser_list->get(1), non_app_url);
    868   SiteInstance* new_instance = popup_contents->GetSiteInstance();
    869   EXPECT_NE(app_instance, new_instance);
    870 
    871   // It should still be in the same BrowsingInstance, allowing postMessage to
    872   // work.
    873   EXPECT_TRUE(app_instance->IsRelatedSiteInstance(new_instance));
    874 }
    875