Home | History | Annotate | Download | only in declarative
      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/bind.h"
      6 #include "base/bind_helpers.h"
      7 #include "base/command_line.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/test/thread_test_helper.h"
     12 #include "chrome/browser/extensions/extension_apitest.h"
     13 #include "chrome/browser/extensions/test_extension_dir.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     16 #include "chrome/test/base/ui_test_utils.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "extensions/browser/api/declarative/rules_registry_service.h"
     19 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
     20 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
     21 #include "extensions/browser/extension_prefs.h"
     22 #include "extensions/common/extension.h"
     23 #include "extensions/test/extension_test_message_listener.h"
     24 
     25 using content::BrowserThread;
     26 using extensions::Extension;
     27 using extensions::ExtensionPrefs;
     28 using extensions::RulesRegistry;
     29 using extensions::RulesRegistryService;
     30 using extensions::TestExtensionDir;
     31 using extensions::WebRequestRulesRegistry;
     32 
     33 namespace {
     34 
     35 const char kArbitraryUrl[] = "http://www.example.com";  // Must be http://.
     36 
     37 // The extension in "declarative/redirect_to_data" redirects every navigation to
     38 // a page with title |kTestTitle|.
     39 #define TEST_TITLE_STRING ":TEST:"
     40 const char kTestTitle[] = TEST_TITLE_STRING;
     41 
     42 // All methods and constands below containing "RedirectToData" in their names
     43 // are parts of a test extension "Redirect to 'data:'".
     44 std::string GetRedirectToDataManifestWithVersion(unsigned version) {
     45   return base::StringPrintf(
     46       "{\n"
     47       "  \"name\": \"Redirect to 'data:' (declarative apitest)\",\n"
     48       "  \"version\": \"%d\",\n"
     49       "  \"manifest_version\": 2,\n"
     50       "  \"description\": \"Redirects all requests to a fixed data: URI.\",\n"
     51       "  \"background\": {\n"
     52       "    \"scripts\": [\"background.js\"]\n"
     53       "  },\n"
     54       "  \"permissions\": [\n"
     55       "    \"declarativeWebRequest\", \"<all_urls>\"\n"
     56       "  ]\n"
     57       "}\n",
     58       version);
     59 }
     60 
     61 const char kRedirectToDataConstants[] =
     62     "var redirectDataURI =\n"
     63     "    'data:text/html;charset=utf-8,<html><head><title>' +\n"
     64     "    '" TEST_TITLE_STRING "' +\n"
     65     "    '<%2Ftitle><%2Fhtml>';\n";
     66 #undef TEST_TITLE_STRING
     67 
     68 const char kRedirectToDataRules[] =
     69     "var rules = [{\n"
     70     "  conditions: [\n"
     71     "    new chrome.declarativeWebRequest.RequestMatcher({\n"
     72     "        url: {schemes: ['http']}})\n"
     73     "  ],\n"
     74     "  actions: [\n"
     75     "    new chrome.declarativeWebRequest.RedirectRequest({\n"
     76     "      redirectUrl: redirectDataURI\n"
     77     "    })\n"
     78     "  ]\n"
     79     "}];\n";
     80 
     81 const char kRedirectToDataInstallRules[] =
     82     "function report(details) {\n"
     83     "  if (chrome.extension.lastError) {\n"
     84     "    chrome.test.log(chrome.extension.lastError.message);\n"
     85     "  } else {\n"
     86     "    chrome.test.sendMessage(\"ready\", function(reply) {})\n"
     87     "  }\n"
     88     "}\n"
     89     "\n"
     90     "chrome.runtime.onInstalled.addListener(function(details) {\n"
     91     "  if (details.reason == 'install')\n"
     92     "    chrome.declarativeWebRequest.onRequest.addRules(rules, report);\n"
     93     "});\n";
     94 
     95 const char kRedirectToDataNoRules[] =
     96     "chrome.runtime.onInstalled.addListener(function(details) {\n"
     97     "  chrome.test.sendMessage(\"ready\", function(reply) {})\n"
     98     "});\n";
     99 
    100 }  // namespace
    101 
    102 class DeclarativeApiTest : public ExtensionApiTest {
    103  public:
    104   std::string GetTitle() {
    105     base::string16 title(
    106         browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
    107     return base::UTF16ToUTF8(title);
    108   }
    109 
    110   // Reports the number of rules registered for the |extension_id| with the
    111   // non-webview rules registry.
    112   size_t NumberOfRegisteredRules(const std::string& extension_id) {
    113     RulesRegistryService* rules_registry_service =
    114         extensions::RulesRegistryService::Get(browser()->profile());
    115     scoped_refptr<RulesRegistry> rules_registry =
    116         rules_registry_service->GetRulesRegistry(
    117             RulesRegistry::WebViewKey(0, 0),
    118             extensions::declarative_webrequest_constants::kOnRequest);
    119     std::vector<linked_ptr<RulesRegistry::Rule> > rules;
    120     BrowserThread::PostTask(
    121         BrowserThread::IO,
    122         FROM_HERE,
    123         base::Bind(
    124             &RulesRegistry::GetAllRules, rules_registry, extension_id, &rules));
    125     scoped_refptr<base::ThreadTestHelper> io_helper(new base::ThreadTestHelper(
    126         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()));
    127     EXPECT_TRUE(io_helper->Run());
    128     return rules.size();
    129   }
    130 };
    131 
    132 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, DeclarativeApi) {
    133   ASSERT_TRUE(RunExtensionTest("declarative/api")) << message_;
    134 
    135   // Check that uninstalling the extension has removed all rules.
    136   std::string extension_id = GetSingleLoadedExtension()->id();
    137   UninstallExtension(extension_id);
    138 
    139   // UnloadExtension posts a task to the owner thread of the extension
    140   // to process this unloading. The next task to retrive all rules
    141   // is therefore processed after the UnloadExtension task has been executed.
    142   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
    143 }
    144 
    145 // PersistRules test first installs an extension, which registers some rules.
    146 // Then after browser restart, it checks that the rules are still in effect.
    147 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, PRE_PersistRules) {
    148   // Note that we cannot use an extension generated by *GetRedirectToData*
    149   // helpers in a TestExtensionDir, because we need the extension to persist
    150   // until the PersistRules test is run.
    151   ASSERT_TRUE(RunExtensionTest("declarative/redirect_to_data")) << message_;
    152 }
    153 
    154 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, PersistRules) {
    155   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    156   EXPECT_EQ(kTestTitle, GetTitle());
    157 }
    158 
    159 // Test that the rules are correctly persisted and (de)activated during
    160 // changing the "installed" and "enabled" status of an extension.
    161 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, ExtensionLifetimeRulesHandling) {
    162   TestExtensionDir ext_dir;
    163 
    164   // 1. Install the extension. Rules should become active.
    165   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(1));
    166   ext_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
    167                     base::StringPrintf("%s%s%s",
    168                                        kRedirectToDataConstants,
    169                                        kRedirectToDataRules,
    170                                        kRedirectToDataInstallRules));
    171   ExtensionTestMessageListener ready("ready", /*will_reply=*/false);
    172   const Extension* extension = InstallExtensionWithUIAutoConfirm(
    173       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
    174   ASSERT_TRUE(extension);
    175   std::string extension_id(extension->id());
    176   ASSERT_TRUE(ready.WaitUntilSatisfied());
    177   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    178   EXPECT_EQ(kTestTitle, GetTitle());
    179   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    180 
    181   // 2. Disable the extension. Rules are no longer active, but are still
    182   // registered.
    183   DisableExtension(extension_id);
    184   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    185   EXPECT_NE(kTestTitle, GetTitle());
    186   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    187 
    188   // 3. Enable the extension again. Rules are active again.
    189   EnableExtension(extension_id);
    190   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    191   EXPECT_EQ(kTestTitle, GetTitle());
    192   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    193 
    194   // 4. Bump the version and update, without the code to add the rules. Rules
    195   // are still active, because the registry does not drop them unless the
    196   // extension gets uninstalled.
    197   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(2));
    198   ext_dir.WriteFile(
    199       FILE_PATH_LITERAL("background.js"),
    200       base::StringPrintf(
    201           "%s%s", kRedirectToDataConstants, kRedirectToDataNoRules));
    202   ExtensionTestMessageListener ready_after_update("ready",
    203                                                   /*will_reply=*/false);
    204   EXPECT_TRUE(UpdateExtension(
    205       extension_id, ext_dir.Pack(), 0 /*no new installed extension*/));
    206   ASSERT_TRUE(ready_after_update.WaitUntilSatisfied());
    207   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    208   EXPECT_EQ(kTestTitle, GetTitle());
    209   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    210 
    211   // 5. Reload the extension. Rules remain active.
    212   ReloadExtension(extension_id);
    213   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    214   EXPECT_EQ(kTestTitle, GetTitle());
    215   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    216 
    217   // 6. Uninstall the extension. Rules are gone.
    218   UninstallExtension(extension_id);
    219   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    220   EXPECT_NE(kTestTitle, GetTitle());
    221   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
    222 }
    223 
    224 // When an extenion is uninstalled, the state store deletes all preferences
    225 // stored for that extension. We need to make sure we don't store anything after
    226 // that deletion occurs.
    227 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, NoTracesAfterUninstalling) {
    228   TestExtensionDir ext_dir;
    229 
    230   // 1. Install the extension. Verify that rules become active and some prefs
    231   // are stored.
    232   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(1));
    233   ext_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
    234                     base::StringPrintf("%s%s%s",
    235                                        kRedirectToDataConstants,
    236                                        kRedirectToDataRules,
    237                                        kRedirectToDataInstallRules));
    238   ExtensionTestMessageListener ready("ready", /*will_reply=*/false);
    239   const Extension* extension = InstallExtensionWithUIAutoConfirm(
    240       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
    241   ASSERT_TRUE(extension);
    242   std::string extension_id(extension->id());
    243   ASSERT_TRUE(ready.WaitUntilSatisfied());
    244   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    245   EXPECT_EQ(kTestTitle, GetTitle());
    246   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
    247   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser()->profile());
    248   EXPECT_TRUE(extension_prefs->HasPrefForExtension(extension_id));
    249 
    250   // 2. Uninstall the extension. Rules are gone and preferences should be empty.
    251   UninstallExtension(extension_id);
    252   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
    253   EXPECT_NE(kTestTitle, GetTitle());
    254   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
    255   EXPECT_FALSE(extension_prefs->HasPrefForExtension(extension_id));
    256 }
    257