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 <string>
      6 
      7 #include "base/command_line.h"
      8 #include "base/json/json_reader.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/extensions/extension_browsertest.h"
     13 #include "chrome/browser/extensions/extension_service.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     17 #include "chrome/common/chrome_switches.h"
     18 #include "chrome/common/extensions/extension.h"
     19 #include "chrome/common/extensions/manifest.h"
     20 #include "chrome/test/base/ui_test_utils.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/test/browser_test_utils.h"
     23 #include "net/dns/mock_host_resolver.h"
     24 #include "url/gurl.h"
     25 
     26 using extensions::Extension;
     27 
     28 class ChromeAppAPITest : public ExtensionBrowserTest {
     29  protected:
     30   bool IsAppInstalled() { return IsAppInstalled(""); }
     31   bool IsAppInstalled(const char* frame_xpath) {
     32     const char kGetAppIsInstalled[] =
     33         "window.domAutomationController.send(window.chrome.app.isInstalled);";
     34     bool result;
     35     CHECK(
     36         content::ExecuteScriptInFrameAndExtractBool(
     37             browser()->tab_strip_model()->GetActiveWebContents(),
     38             frame_xpath,
     39             kGetAppIsInstalled,
     40             &result));
     41     return result;
     42   }
     43 
     44   std::string InstallState() { return InstallState(""); }
     45   std::string InstallState(const char* frame_xpath) {
     46     const char kGetAppInstallState[] =
     47         "window.chrome.app.installState("
     48         "    function(s) { window.domAutomationController.send(s); });";
     49     std::string result;
     50     CHECK(
     51         content::ExecuteScriptInFrameAndExtractString(
     52             browser()->tab_strip_model()->GetActiveWebContents(),
     53             frame_xpath,
     54             kGetAppInstallState,
     55             &result));
     56     return result;
     57   }
     58 
     59   std::string RunningState() { return RunningState(""); }
     60   std::string RunningState(const char* frame_xpath) {
     61     const char kGetAppRunningState[] =
     62         "window.domAutomationController.send("
     63         "    window.chrome.app.runningState());";
     64     std::string result;
     65     CHECK(
     66         content::ExecuteScriptInFrameAndExtractString(
     67             browser()->tab_strip_model()->GetActiveWebContents(),
     68             frame_xpath,
     69             kGetAppRunningState,
     70             &result));
     71     return result;
     72   }
     73 
     74  private:
     75   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     76     ExtensionBrowserTest::SetUpCommandLine(command_line);
     77     command_line->AppendSwitchASCII(switches::kAppsCheckoutURL,
     78                                     "http://checkout.com:");
     79   }
     80 };
     81 
     82 // Flaky http://crbug.com/238674
     83 #if defined(OS_WIN)
     84 #define MAYBE_IsInstalled DISABLED_IsInstalled
     85 #else
     86 #define MAYBE_IsInstalled IsInstalled
     87 #endif
     88 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, MAYBE_IsInstalled) {
     89   std::string app_host("app.com");
     90   std::string nonapp_host("nonapp.com");
     91 
     92   host_resolver()->AddRule(app_host, "127.0.0.1");
     93   host_resolver()->AddRule(nonapp_host, "127.0.0.1");
     94   ASSERT_TRUE(test_server()->Start());
     95 
     96   GURL test_file_url(test_server()->GetURL("extensions/test_file.html"));
     97   GURL::Replacements replace_host;
     98 
     99   replace_host.SetHostStr(app_host);
    100   GURL app_url(test_file_url.ReplaceComponents(replace_host));
    101 
    102   replace_host.SetHostStr(nonapp_host);
    103   GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
    104 
    105   // Before the app is installed, app.com does not think that it is installed
    106   ui_test_utils::NavigateToURL(browser(), app_url);
    107   EXPECT_FALSE(IsAppInstalled());
    108 
    109   // Load an app which includes app.com in its extent.
    110   const Extension* extension = LoadExtension(
    111       test_data_dir_.AppendASCII("app_dot_com_app"));
    112   ASSERT_TRUE(extension);
    113 
    114   // Even after the app is installed, the existing app.com tab is not in an
    115   // app process, so chrome.app.isInstalled should return false.
    116   EXPECT_FALSE(IsAppInstalled());
    117 
    118   // Test that a non-app page has chrome.app.isInstalled = false.
    119   ui_test_utils::NavigateToURL(browser(), non_app_url);
    120   EXPECT_FALSE(IsAppInstalled());
    121 
    122   // Test that a non-app page returns null for chrome.app.getDetails().
    123   const char kGetAppDetails[] =
    124       "window.domAutomationController.send("
    125       "    JSON.stringify(window.chrome.app.getDetails()));";
    126   std::string result;
    127   ASSERT_TRUE(
    128       content::ExecuteScriptAndExtractString(
    129           browser()->tab_strip_model()->GetActiveWebContents(),
    130           kGetAppDetails,
    131           &result));
    132   EXPECT_EQ("null", result);
    133 
    134   // Check that an app page has chrome.app.isInstalled = true.
    135   ui_test_utils::NavigateToURL(browser(), app_url);
    136   EXPECT_TRUE(IsAppInstalled());
    137 
    138   // Check that an app page returns the correct result for
    139   // chrome.app.getDetails().
    140   ui_test_utils::NavigateToURL(browser(), app_url);
    141   ASSERT_TRUE(
    142       content::ExecuteScriptAndExtractString(
    143           browser()->tab_strip_model()->GetActiveWebContents(),
    144           kGetAppDetails,
    145           &result));
    146   scoped_ptr<DictionaryValue> app_details(
    147       static_cast<DictionaryValue*>(base::JSONReader::Read(result)));
    148   // extension->manifest() does not contain the id.
    149   app_details->Remove("id", NULL);
    150   EXPECT_TRUE(app_details.get());
    151   EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
    152 
    153   // Try to change app.isInstalled.  Should silently fail, so
    154   // that isInstalled should have the initial value.
    155   ASSERT_TRUE(
    156       content::ExecuteScriptAndExtractString(
    157           browser()->tab_strip_model()->GetActiveWebContents(),
    158           "window.domAutomationController.send("
    159           "    function() {"
    160           "        var value = window.chrome.app.isInstalled;"
    161           "        window.chrome.app.isInstalled = !value;"
    162           "        if (window.chrome.app.isInstalled == value) {"
    163           "            return 'true';"
    164           "        } else {"
    165           "            return 'false';"
    166           "        }"
    167           "    }()"
    168           ");",
    169           &result));
    170 
    171   // Should not be able to alter window.chrome.app.isInstalled from javascript";
    172   EXPECT_EQ("true", result);
    173 }
    174 
    175 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, GetDetailsForFrame) {
    176   std::string app_host("app.com");
    177   std::string nonapp_host("nonapp.com");
    178   std::string checkout_host("checkout.com");
    179 
    180   host_resolver()->AddRule(app_host, "127.0.0.1");
    181   host_resolver()->AddRule(nonapp_host, "127.0.0.1");
    182   host_resolver()->AddRule(checkout_host, "127.0.0.1");
    183   ASSERT_TRUE(test_server()->Start());
    184 
    185   GURL test_file_url(test_server()->GetURL(
    186       "files/extensions/get_app_details_for_frame.html"));
    187   GURL::Replacements replace_host;
    188 
    189   replace_host.SetHostStr(checkout_host);
    190   GURL checkout_url(test_file_url.ReplaceComponents(replace_host));
    191 
    192   replace_host.SetHostStr(app_host);
    193   GURL app_url(test_file_url.ReplaceComponents(replace_host));
    194 
    195   // Load an app which includes app.com in its extent.
    196   const Extension* extension = LoadExtension(
    197       test_data_dir_.AppendASCII("app_dot_com_app"));
    198   ASSERT_TRUE(extension);
    199 
    200   // Test that normal pages (even apps) cannot use getDetailsForFrame().
    201   ui_test_utils::NavigateToURL(browser(), app_url);
    202   const char kTestUnsuccessfulAccess[] =
    203       "window.domAutomationController.send(window.testUnsuccessfulAccess())";
    204   bool result = false;
    205   ASSERT_TRUE(
    206       content::ExecuteScriptAndExtractBool(
    207           browser()->tab_strip_model()->GetActiveWebContents(),
    208           kTestUnsuccessfulAccess,
    209           &result));
    210   EXPECT_TRUE(result);
    211 
    212   // Test that checkout can use getDetailsForFrame() and that it works
    213   // correctly.
    214   ui_test_utils::NavigateToURL(browser(), checkout_url);
    215   const char kGetDetailsForFrame[] =
    216       "window.domAutomationController.send("
    217       "    JSON.stringify(chrome.app.getDetailsForFrame(frames[0])))";
    218   std::string json;
    219   ASSERT_TRUE(
    220       content::ExecuteScriptAndExtractString(
    221           browser()->tab_strip_model()->GetActiveWebContents(),
    222           kGetDetailsForFrame,
    223           &json));
    224 
    225   scoped_ptr<DictionaryValue> app_details(
    226       static_cast<DictionaryValue*>(base::JSONReader::Read(json)));
    227   // extension->manifest() does not contain the id.
    228   app_details->Remove("id", NULL);
    229   EXPECT_TRUE(app_details.get());
    230   EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
    231 }
    232 
    233 
    234 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
    235   std::string app_host("app.com");
    236   std::string non_app_host("nonapp.com");
    237 
    238   host_resolver()->AddRule(app_host, "127.0.0.1");
    239   host_resolver()->AddRule(non_app_host, "127.0.0.1");
    240   ASSERT_TRUE(test_server()->Start());
    241 
    242   GURL test_file_url(test_server()->GetURL(
    243       "files/extensions/get_app_details_for_frame.html"));
    244   GURL::Replacements replace_host;
    245 
    246   replace_host.SetHostStr(app_host);
    247   GURL app_url(test_file_url.ReplaceComponents(replace_host));
    248 
    249   replace_host.SetHostStr(non_app_host);
    250   GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
    251 
    252   // Before the app is installed, app.com does not think that it is installed
    253   ui_test_utils::NavigateToURL(browser(), app_url);
    254 
    255   EXPECT_EQ("not_installed", InstallState());
    256   EXPECT_EQ("cannot_run", RunningState());
    257   EXPECT_FALSE(IsAppInstalled());
    258 
    259   const Extension* extension = LoadExtension(
    260       test_data_dir_.AppendASCII("app_dot_com_app"));
    261   ASSERT_TRUE(extension);
    262 
    263   EXPECT_EQ("installed", InstallState());
    264   EXPECT_EQ("ready_to_run", RunningState());
    265   EXPECT_FALSE(IsAppInstalled());
    266 
    267   // Reloading the page should put the tab in an app process.
    268   ui_test_utils::NavigateToURL(browser(), app_url);
    269   EXPECT_EQ("installed", InstallState());
    270   EXPECT_EQ("running", RunningState());
    271   EXPECT_TRUE(IsAppInstalled());
    272 
    273   // Disable the extension and verify the state.
    274   browser()->profile()->GetExtensionService()->DisableExtension(
    275       extension->id(), Extension::DISABLE_PERMISSIONS_INCREASE);
    276   ui_test_utils::NavigateToURL(browser(), app_url);
    277 
    278   EXPECT_EQ("disabled", InstallState());
    279   EXPECT_EQ("cannot_run", RunningState());
    280   EXPECT_FALSE(IsAppInstalled());
    281 
    282   browser()->profile()->GetExtensionService()->EnableExtension(extension->id());
    283   EXPECT_EQ("installed", InstallState());
    284   EXPECT_EQ("ready_to_run", RunningState());
    285   EXPECT_FALSE(IsAppInstalled());
    286 
    287   // The non-app URL should still not be installed or running.
    288   ui_test_utils::NavigateToURL(browser(), non_app_url);
    289 
    290   EXPECT_EQ("not_installed", InstallState());
    291   EXPECT_EQ("cannot_run", RunningState());
    292   EXPECT_FALSE(IsAppInstalled());
    293 
    294   EXPECT_EQ("installed", InstallState("//html/iframe[1]"));
    295   EXPECT_EQ("cannot_run", RunningState("//html/iframe[1]"));
    296   EXPECT_FALSE(IsAppInstalled("//html/iframe[1]"));
    297 
    298 }
    299 
    300 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
    301   std::string app_host("app.com");
    302   std::string non_app_host("nonapp.com");
    303 
    304   host_resolver()->AddRule(app_host, "127.0.0.1");
    305   host_resolver()->AddRule(non_app_host, "127.0.0.1");
    306   ASSERT_TRUE(test_server()->Start());
    307 
    308   GURL test_file_url(test_server()->GetURL(
    309       "files/extensions/get_app_details_for_frame_reversed.html"));
    310   GURL::Replacements replace_host;
    311 
    312   replace_host.SetHostStr(app_host);
    313   GURL app_url(test_file_url.ReplaceComponents(replace_host));
    314 
    315   replace_host.SetHostStr(non_app_host);
    316   GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
    317 
    318   // Check the install and running state of a non-app iframe running
    319   // within an app.
    320   ui_test_utils::NavigateToURL(browser(), app_url);
    321 
    322   EXPECT_EQ("not_installed", InstallState("//html/iframe[1]"));
    323   EXPECT_EQ("cannot_run", RunningState("//html/iframe[1]"));
    324   EXPECT_FALSE(IsAppInstalled("//html/iframe[1]"));
    325 }
    326