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