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 <vector>
      6 
      7 #include "base/command_line.h"
      8 #include "base/file_util.h"
      9 #include "base/files/file_path.h"
     10 #include "base/path_service.h"
     11 #include "base/strings/string_util.h"
     12 #include "chrome/browser/chrome_notification_types.h"
     13 #include "chrome/browser/extensions/extension_service.h"
     14 #include "chrome/browser/extensions/extension_system.h"
     15 #include "chrome/browser/extensions/user_script_master.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/ui/browser.h"
     18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     19 #include "chrome/common/chrome_paths.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/extensions/feature_switch.h"
     22 #include "chrome/test/base/in_process_browser_test.h"
     23 #include "chrome/test/base/testing_profile.h"
     24 #include "chrome/test/base/ui_test_utils.h"
     25 #include "content/public/browser/notification_details.h"
     26 #include "content/public/browser/notification_service.h"
     27 #include "content/public/browser/web_contents.h"
     28 #include "content/public/test/browser_test_utils.h"
     29 #include "net/base/net_util.h"
     30 
     31 using extensions::FeatureSwitch;
     32 
     33 // This file contains high-level startup tests for the extensions system. We've
     34 // had many silly bugs where command line flags did not get propagated correctly
     35 // into the services, so we didn't start correctly.
     36 
     37 class ExtensionStartupTestBase : public InProcessBrowserTest {
     38  public:
     39   ExtensionStartupTestBase() :
     40       enable_extensions_(false) {
     41     num_expected_extensions_ = 3;
     42   }
     43 
     44  protected:
     45   // InProcessBrowserTest
     46   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     47     if (!enable_extensions_)
     48       command_line->AppendSwitch(switches::kDisableExtensions);
     49 
     50     if (!load_extensions_.empty()) {
     51       base::FilePath::StringType paths = JoinString(load_extensions_, ',');
     52       command_line->AppendSwitchNative(switches::kLoadExtension,
     53                                        paths);
     54       command_line->AppendSwitch(switches::kDisableExtensionsFileAccessCheck);
     55     }
     56   }
     57 
     58   virtual bool SetUpUserDataDirectory() OVERRIDE {
     59     base::FilePath profile_dir;
     60     PathService::Get(chrome::DIR_USER_DATA, &profile_dir);
     61     profile_dir = profile_dir.AppendASCII(TestingProfile::kTestUserProfileDir);
     62     file_util::CreateDirectory(profile_dir);
     63 
     64     preferences_file_ = profile_dir.AppendASCII("Preferences");
     65     user_scripts_dir_ = profile_dir.AppendASCII("User Scripts");
     66     extensions_dir_ = profile_dir.AppendASCII("Extensions");
     67 
     68     if (enable_extensions_ && load_extensions_.empty()) {
     69       base::FilePath src_dir;
     70       PathService::Get(chrome::DIR_TEST_DATA, &src_dir);
     71       src_dir = src_dir.AppendASCII("extensions").AppendASCII("good");
     72 
     73       base::CopyFile(src_dir.AppendASCII("Preferences"), preferences_file_);
     74       base::CopyDirectory(src_dir.AppendASCII("Extensions"),
     75                           profile_dir, true);  // recursive
     76     }
     77     return true;
     78   }
     79 
     80   virtual void TearDown() {
     81     EXPECT_TRUE(base::DeleteFile(preferences_file_, false));
     82 
     83     // TODO(phajdan.jr): Check return values of the functions below, carefully.
     84     base::DeleteFile(user_scripts_dir_, true);
     85     base::DeleteFile(extensions_dir_, true);
     86 
     87     InProcessBrowserTest::TearDown();
     88   }
     89 
     90   void WaitForServicesToStart(int num_expected_extensions,
     91                               bool expect_extensions_enabled) {
     92     ExtensionService* service = extensions::ExtensionSystem::Get(
     93         browser()->profile())->extension_service();
     94 
     95     // Count the number of non-component extensions.
     96     int found_extensions = 0;
     97     for (ExtensionSet::const_iterator it = service->extensions()->begin();
     98          it != service->extensions()->end(); ++it)
     99       if ((*it)->location() != extensions::Manifest::COMPONENT)
    100         found_extensions++;
    101 
    102     ASSERT_EQ(static_cast<uint32>(num_expected_extensions),
    103               static_cast<uint32>(found_extensions));
    104     ASSERT_EQ(expect_extensions_enabled, service->extensions_enabled());
    105 
    106     content::WindowedNotificationObserver user_scripts_observer(
    107         chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
    108         content::NotificationService::AllSources());
    109     extensions::UserScriptMaster* master =
    110         extensions::ExtensionSystem::Get(browser()->profile())->
    111             user_script_master();
    112     if (!master->ScriptsReady())
    113       user_scripts_observer.Wait();
    114     ASSERT_TRUE(master->ScriptsReady());
    115   }
    116 
    117   void TestInjection(bool expect_css, bool expect_script) {
    118     // Load a page affected by the content script and test to see the effect.
    119     base::FilePath test_file;
    120     PathService::Get(chrome::DIR_TEST_DATA, &test_file);
    121     test_file = test_file.AppendASCII("extensions")
    122                          .AppendASCII("test_file.html");
    123 
    124     ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(test_file));
    125 
    126     bool result = false;
    127     ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    128         browser()->tab_strip_model()->GetActiveWebContents(),
    129         "window.domAutomationController.send("
    130         "    document.defaultView.getComputedStyle(document.body, null)."
    131         "    getPropertyValue('background-color') == 'rgb(245, 245, 220)')",
    132         &result));
    133     EXPECT_EQ(expect_css, result);
    134 
    135     result = false;
    136     ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    137         browser()->tab_strip_model()->GetActiveWebContents(),
    138         "window.domAutomationController.send(document.title == 'Modified')",
    139         &result));
    140     EXPECT_EQ(expect_script, result);
    141   }
    142 
    143   base::FilePath preferences_file_;
    144   base::FilePath extensions_dir_;
    145   base::FilePath user_scripts_dir_;
    146   bool enable_extensions_;
    147   // Extensions to load from the command line.
    148   std::vector<base::FilePath::StringType> load_extensions_;
    149 
    150   int num_expected_extensions_;
    151 };
    152 
    153 
    154 // ExtensionsStartupTest
    155 // Ensures that we can startup the browser with --enable-extensions and some
    156 // extensions installed and see them run and do basic things.
    157 
    158 class ExtensionsStartupTest : public ExtensionStartupTestBase {
    159  public:
    160   ExtensionsStartupTest() {
    161     enable_extensions_ = true;
    162   }
    163 };
    164 
    165 IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) {
    166   WaitForServicesToStart(num_expected_extensions_, true);
    167   TestInjection(true, true);
    168 }
    169 
    170 // Sometimes times out on Mac.  http://crbug.com/48151
    171 #if defined(OS_MACOSX)
    172 #define MAYBE_NoFileAccess DISABLED_NoFileAccess
    173 #else
    174 #define MAYBE_NoFileAccess NoFileAccess
    175 #endif
    176 // Tests that disallowing file access on an extension prevents it from injecting
    177 // script into a page with a file URL.
    178 IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
    179   WaitForServicesToStart(num_expected_extensions_, true);
    180 
    181   // Keep a separate list of extensions for which to disable file access, since
    182   // doing so reloads them.
    183   std::vector<const extensions::Extension*> extension_list;
    184 
    185   ExtensionService* service = extensions::ExtensionSystem::Get(
    186       browser()->profile())->extension_service();
    187   for (ExtensionSet::const_iterator it = service->extensions()->begin();
    188        it != service->extensions()->end(); ++it) {
    189     if ((*it)->location() == extensions::Manifest::COMPONENT)
    190       continue;
    191     if (service->AllowFileAccess(it->get()))
    192       extension_list.push_back(it->get());
    193   }
    194 
    195   for (size_t i = 0; i < extension_list.size(); ++i) {
    196     content::WindowedNotificationObserver user_scripts_observer(
    197         chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
    198         content::NotificationService::AllSources());
    199     service->SetAllowFileAccess(extension_list[i], false);
    200     user_scripts_observer.Wait();
    201   }
    202 
    203   TestInjection(false, false);
    204 }
    205 
    206 // ExtensionsLoadTest
    207 // Ensures that we can startup the browser with --load-extension and see them
    208 // run.
    209 
    210 class ExtensionsLoadTest : public ExtensionStartupTestBase {
    211  public:
    212   ExtensionsLoadTest() {
    213     enable_extensions_ = true;
    214     base::FilePath one_extension_path;
    215     PathService::Get(chrome::DIR_TEST_DATA, &one_extension_path);
    216     one_extension_path = one_extension_path
    217         .AppendASCII("extensions")
    218         .AppendASCII("good")
    219         .AppendASCII("Extensions")
    220         .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
    221         .AppendASCII("1.0.0.0");
    222     load_extensions_.push_back(one_extension_path.value());
    223   }
    224 };
    225 
    226 // Fails inconsistently on Linux x64. http://crbug.com/80961
    227 // TODO(dpapad): Has not failed since October 2011, let's reenable, monitor
    228 // and act accordingly.
    229 IN_PROC_BROWSER_TEST_F(ExtensionsLoadTest, Test) {
    230   WaitForServicesToStart(1, true);
    231   TestInjection(true, true);
    232 }
    233 
    234 // ExtensionsLoadMultipleTest
    235 // Ensures that we can startup the browser with multiple extensions
    236 // via --load-extension=X1,X2,X3.
    237 class ExtensionsLoadMultipleTest : public ExtensionStartupTestBase {
    238  public:
    239   ExtensionsLoadMultipleTest() {
    240     enable_extensions_ = true;
    241     base::FilePath one_extension_path;
    242     PathService::Get(chrome::DIR_TEST_DATA, &one_extension_path);
    243     one_extension_path = one_extension_path
    244         .AppendASCII("extensions")
    245         .AppendASCII("good")
    246         .AppendASCII("Extensions")
    247         .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
    248         .AppendASCII("1.0.0.0");
    249     load_extensions_.push_back(one_extension_path.value());
    250 
    251     base::FilePath second_extension_path;
    252     PathService::Get(chrome::DIR_TEST_DATA, &second_extension_path);
    253     second_extension_path = second_extension_path
    254         .AppendASCII("extensions")
    255         .AppendASCII("app");
    256     load_extensions_.push_back(second_extension_path.value());
    257 
    258     base::FilePath third_extension_path;
    259     PathService::Get(chrome::DIR_TEST_DATA, &third_extension_path);
    260     third_extension_path = third_extension_path
    261         .AppendASCII("extensions")
    262         .AppendASCII("app1");
    263     load_extensions_.push_back(third_extension_path.value());
    264 
    265     base::FilePath fourth_extension_path;
    266     PathService::Get(chrome::DIR_TEST_DATA, &fourth_extension_path);
    267     fourth_extension_path = fourth_extension_path
    268         .AppendASCII("extensions")
    269         .AppendASCII("app2");
    270     load_extensions_.push_back(fourth_extension_path.value());
    271   }
    272 };
    273 
    274 IN_PROC_BROWSER_TEST_F(ExtensionsLoadMultipleTest, Test) {
    275   WaitForServicesToStart(4, true);
    276   TestInjection(true, true);
    277 }
    278