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 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_ 6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_ 7 8 #include <string> 9 10 #include "base/command_line.h" 11 #include "base/files/file_path.h" 12 #include "base/files/scoped_temp_dir.h" 13 #include "base/macros.h" 14 #include "base/test/scoped_path_override.h" 15 #include "build/build_config.h" 16 #include "chrome/browser/extensions/chrome_extension_test_notification_observer.h" 17 #include "chrome/browser/extensions/install_verifier.h" 18 #include "chrome/browser/extensions/updater/extension_updater.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/ui/browser.h" 21 #include "chrome/test/base/in_process_browser_test.h" 22 #include "content/public/browser/web_contents.h" 23 #include "extensions/browser/browsertest_util.h" 24 #include "extensions/browser/extension_creator.h" 25 #include "extensions/browser/extension_host.h" 26 #include "extensions/browser/extension_protocols.h" 27 #include "extensions/browser/extension_registry.h" 28 #include "extensions/browser/extension_system.h" 29 #include "extensions/browser/sandboxed_unpacker.h" 30 #include "extensions/browser/scoped_ignore_content_verifier_for_test.h" 31 #include "extensions/common/extension.h" 32 #include "extensions/common/feature_switch.h" 33 #include "extensions/common/features/feature_channel.h" 34 #include "extensions/common/manifest.h" 35 36 class Profile; 37 38 namespace extensions { 39 class ExtensionCacheFake; 40 class ExtensionService; 41 class ExtensionSet; 42 class ProcessManager; 43 44 // Base class for extension browser tests. Provides utilities for loading, 45 // unloading, and installing extensions. 46 class ExtensionBrowserTest : virtual public InProcessBrowserTest { 47 public: 48 // Different types of extension's lazy background contexts used in some tests. 49 enum class ContextType { 50 // A non-persistent background page/JS based extension. 51 kEventPage, 52 // A Service Worker based extension. 53 kServiceWorker, 54 // An extension with a persistent background page. 55 kPersistentBackground, 56 }; 57 58 protected: 59 // Flags used to configure how the tests are run. 60 enum Flags { 61 kFlagNone = 0, 62 63 // Allow the extension to run in incognito mode. 64 kFlagEnableIncognito = 1 << 0, 65 66 // Allow file access for the extension. 67 kFlagEnableFileAccess = 1 << 1, 68 69 // Don't fail when the loaded manifest has warnings (should only be used 70 // when testing deprecated features). 71 kFlagIgnoreManifestWarnings = 1 << 2, 72 73 // Allow older manifest versions (typically these can't be loaded - we allow 74 // them for testing). 75 kFlagAllowOldManifestVersions = 1 << 3, 76 77 // Pass the FOR_LOGIN_SCREEN flag when loading the extension. This flag is 78 // usually provided for force-installed extension on the login screen. 79 kFlagLoadForLoginScreen = 1 << 4, 80 81 // Load the provided extension as Service Worker based extension. 82 kFlagRunAsServiceWorkerBasedExtension = 1 << 5, 83 84 // Don't wait for extension renderers to fully load. 85 kFlagDontWaitForExtensionRenderers = 1 << 6, 86 87 // Always maintain this as the next flag value. The flags in 88 // ExtensionApiTest depend on this to avoid having overlapping 89 // values with these flags. 90 kFlagNextValue = 1 << 7, 91 }; 92 93 ExtensionBrowserTest(); 94 ~ExtensionBrowserTest() override; 95 96 // Useful accessors. extension_service()97 ExtensionService* extension_service() { 98 return ExtensionSystem::Get(profile())->extension_service(); 99 } 100 extension_registry()101 ExtensionRegistry* extension_registry() { 102 return ExtensionRegistry::Get(profile()); 103 } 104 last_loaded_extension_id()105 const std::string& last_loaded_extension_id() { 106 return observer_->last_loaded_extension_id(); 107 } 108 109 // Get the profile to use. 110 virtual Profile* profile(); 111 112 // Extensions used in tests are typically not from the web store and will have 113 // missing content verification hashes. The default implementation disables 114 // content verification; this should be overridden by derived tests which care 115 // about content verification. 116 virtual bool ShouldEnableContentVerification(); 117 118 // Extensions used in tests are typically not from the web store and will fail 119 // install verification. The default implementation disables install 120 // verification; this should be overridden by derived tests which care 121 // about install verification. 122 virtual bool ShouldEnableInstallVerification(); 123 124 // Returns the path of the directory from which to serve resources when they 125 // are prefixed with "_test_resources/". 126 // The default is chrome/test/data/extensions/. 127 virtual base::FilePath GetTestResourcesParentDir(); 128 129 static const Extension* GetExtensionByPath(const ExtensionSet& extensions, 130 const base::FilePath& path); 131 132 // InProcessBrowserTest 133 void SetUp() override; 134 void SetUpCommandLine(base::CommandLine* command_line) override; 135 void SetUpOnMainThread() override; 136 void TearDownOnMainThread() override; 137 138 const Extension* LoadExtension(const base::FilePath& path); 139 140 // Load extension and enable it in incognito mode. 141 const Extension* LoadExtensionIncognito(const base::FilePath& path); 142 143 // Load extension from the |path| folder. |flags| is bit mask of values from 144 // |Flags| enum. 145 const Extension* LoadExtensionWithFlags(const base::FilePath& path, 146 int flags); 147 148 // Same as above, but sets the installation parameter to the extension 149 // preferences. 150 const Extension* LoadExtensionWithInstallParam( 151 const base::FilePath& path, 152 int flags, 153 const std::string& install_param); 154 155 // Converts an extension from |path| to a Service Worker based extension and 156 // returns true on success. 157 // If successful, |out_path| contains path of the converted extension. 158 // 159 // NOTE: The conversion works only for extensions with background.scripts and 160 // background.persistent = false; persistent background pages and 161 // background.page are not supported. 162 bool CreateServiceWorkerBasedExtension(const base::FilePath& path, 163 base::FilePath* out_path); 164 165 // Loads unpacked extension from |path| with manifest |manifest_relative_path| 166 // and imitates that it is a component extension. 167 // |manifest_relative_path| is relative to |path|. 168 const Extension* LoadExtensionAsComponentWithManifest( 169 const base::FilePath& path, 170 const base::FilePath::CharType* manifest_relative_path); 171 172 // Loads unpacked extension from |path| and imitates that it is a component 173 // extension. Equivalent to 174 // LoadExtensionAsComponentWithManifest(path, kManifestFilename). 175 const Extension* LoadExtensionAsComponent(const base::FilePath& path); 176 177 // Loads and launches the app from |path|, and returns it. 178 const Extension* LoadAndLaunchApp(const base::FilePath& path); 179 180 // Launches |extension| as a window and returns the browser. 181 Browser* LaunchAppBrowser(const Extension* extension); 182 183 // Pack the extension in |dir_path| into a crx file and return its path. 184 // Return an empty FilePath if there were errors. 185 base::FilePath PackExtension( 186 const base::FilePath& dir_path, 187 int extra_run_flags = ExtensionCreator::kNoRunFlags); 188 189 // Pack the extension in |dir_path| into a crx file at |crx_path|, using the 190 // key |pem_path|. If |pem_path| does not exist, create a new key at 191 // |pem_out_path|. 192 // Return the path to the crx file, or an empty FilePath if there were errors. 193 base::FilePath PackExtensionWithOptions( 194 const base::FilePath& dir_path, 195 const base::FilePath& crx_path, 196 const base::FilePath& pem_path, 197 const base::FilePath& pem_out_path, 198 int extra_run_flags = ExtensionCreator::kNoRunFlags); 199 200 // |expected_change| indicates how many extensions should be installed (or 201 // disabled, if negative). 202 // 1 means you expect a new install, 0 means you expect an upgrade, -1 means 203 // you expect a failed upgrade. InstallExtension(const base::FilePath & path,int expected_change)204 const Extension* InstallExtension(const base::FilePath& path, 205 int expected_change) { 206 return InstallOrUpdateExtension( 207 std::string(), path, INSTALL_UI_TYPE_NONE, expected_change); 208 } 209 210 // Same as above, but an install source other than Manifest::INTERNAL can be 211 // specified. InstallExtension(const base::FilePath & path,int expected_change,Manifest::Location install_source)212 const Extension* InstallExtension(const base::FilePath& path, 213 int expected_change, 214 Manifest::Location install_source) { 215 return InstallOrUpdateExtension(std::string(), 216 path, 217 INSTALL_UI_TYPE_NONE, 218 expected_change, 219 install_source); 220 } 221 222 // Installs an extension and grants it the permissions it requests. 223 // TODO(devlin): It seems like this is probably the desired outcome most of 224 // the time - otherwise the extension installs in a disabled state. InstallExtensionWithPermissionsGranted(const base::FilePath & file_path,int expected_change)225 const Extension* InstallExtensionWithPermissionsGranted( 226 const base::FilePath& file_path, 227 int expected_change) { 228 return InstallOrUpdateExtension( 229 std::string(), file_path, INSTALL_UI_TYPE_NONE, expected_change, 230 Manifest::INTERNAL, browser(), Extension::NO_FLAGS, false, true); 231 } 232 233 // Installs extension as if it came from the Chrome Webstore. 234 const Extension* InstallExtensionFromWebstore(const base::FilePath& path, 235 int expected_change); 236 237 // Same as above but passes an id to CrxInstaller and does not allow a 238 // privilege increase. UpdateExtension(const std::string & id,const base::FilePath & path,int expected_change)239 const Extension* UpdateExtension(const std::string& id, 240 const base::FilePath& path, 241 int expected_change) { 242 return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE, 243 expected_change); 244 } 245 246 // Same as UpdateExtension but waits for the extension to be idle first. 247 const Extension* UpdateExtensionWaitForIdle(const std::string& id, 248 const base::FilePath& path, 249 int expected_change); 250 InstallExtensionWithUIAutoConfirm(const base::FilePath & path,int expected_change,Browser * browser)251 const Extension* InstallExtensionWithUIAutoConfirm(const base::FilePath& path, 252 int expected_change, 253 Browser* browser) { 254 return InstallOrUpdateExtension( 255 std::string(), path, INSTALL_UI_TYPE_AUTO_CONFIRM, expected_change, 256 browser, Extension::NO_FLAGS); 257 } 258 InstallExtensionWithSourceAndFlags(const base::FilePath & path,int expected_change,Manifest::Location install_source,Extension::InitFromValueFlags creation_flags)259 const Extension* InstallExtensionWithSourceAndFlags( 260 const base::FilePath& path, 261 int expected_change, 262 Manifest::Location install_source, 263 Extension::InitFromValueFlags creation_flags) { 264 return InstallOrUpdateExtension(std::string(), path, INSTALL_UI_TYPE_NONE, 265 expected_change, install_source, browser(), 266 creation_flags, false, false); 267 } 268 269 // Begins install process but simulates a user cancel. StartInstallButCancel(const base::FilePath & path)270 const Extension* StartInstallButCancel(const base::FilePath& path) { 271 return InstallOrUpdateExtension( 272 std::string(), path, INSTALL_UI_TYPE_CANCEL, 0); 273 } 274 275 void ReloadExtension(const std::string& extension_id); 276 277 void UnloadExtension(const std::string& extension_id); 278 279 void UninstallExtension(const std::string& extension_id); 280 281 void DisableExtension(const std::string& extension_id); 282 283 void EnableExtension(const std::string& extension_id); 284 285 // Wait for the number of visible page actions to change to |count|. WaitForPageActionVisibilityChangeTo(int count)286 bool WaitForPageActionVisibilityChangeTo(int count) { 287 return observer_->WaitForPageActionVisibilityChangeTo(count); 288 } 289 290 // Wait for the specified extension to crash. Returns true if it really 291 // crashed. WaitForExtensionCrash(const std::string & extension_id)292 bool WaitForExtensionCrash(const std::string& extension_id) { 293 return observer_->WaitForExtensionCrash(extension_id); 294 } 295 296 // Wait for the crx installer to be done. Returns true if it has finished 297 // successfully. WaitForCrxInstallerDone()298 bool WaitForCrxInstallerDone() { 299 return observer_->WaitForCrxInstallerDone(); 300 } 301 302 // Wait for all extension views to load. WaitForExtensionViewsToLoad()303 bool WaitForExtensionViewsToLoad() { 304 return observer_->WaitForExtensionViewsToLoad(); 305 } 306 307 // Wait for the extension to be idle. WaitForExtensionIdle(const std::string & extension_id)308 bool WaitForExtensionIdle(const std::string& extension_id) { 309 return observer_->WaitForExtensionIdle(extension_id); 310 } 311 312 // Wait for the extension to not be idle. WaitForExtensionNotIdle(const std::string & extension_id)313 bool WaitForExtensionNotIdle(const std::string& extension_id) { 314 return observer_->WaitForExtensionNotIdle(extension_id); 315 } 316 317 // Simulates a page calling window.open on an URL and waits for the 318 // navigation. 319 // |should_succeed| indicates whether the navigation should succeed, in which 320 // case the last committed url should match the passed url and the page should 321 // not be an error or interstitial page. 322 void OpenWindow(content::WebContents* contents, 323 const GURL& url, 324 bool newtab_process_should_equal_opener, 325 bool should_succeed, 326 content::WebContents** newtab_result); 327 328 // Simulates a page navigating itself to an URL and waits for the 329 // navigation. 330 void NavigateInRenderer(content::WebContents* contents, const GURL& url); 331 332 // Looks for an ExtensionHost whose URL has the given path component 333 // (including leading slash). Also verifies that the expected number of hosts 334 // are loaded. 335 ExtensionHost* FindHostWithPath(ProcessManager* manager, 336 const std::string& path, 337 int expected_hosts); 338 339 // Returns 340 // browsertest_util::ExecuteScriptInBackgroundPage(profile(), 341 // extension_id, script). 342 std::string ExecuteScriptInBackgroundPage( 343 const std::string& extension_id, 344 const std::string& script, 345 extensions::browsertest_util::ScriptUserActivation 346 script_user_activation = 347 extensions::browsertest_util::ScriptUserActivation::kActivate); 348 349 // Returns 350 // browsertest_util::ExecuteScriptInBackgroundPageNoWait( 351 // profile(), extension_id, script). 352 bool ExecuteScriptInBackgroundPageNoWait(const std::string& extension_id, 353 const std::string& script); 354 355 #if defined(OS_CHROMEOS) 356 // True if the command line should be tweaked as if ChromeOS user is 357 // already logged in. 358 bool set_chromeos_user_; 359 #endif 360 361 // Set to "chrome/test/data/extensions". Derived classes may override. 362 // TODO(michaelpg): Don't override protected data members. 363 base::FilePath test_data_dir_; 364 365 std::unique_ptr<ChromeExtensionTestNotificationObserver> observer_; 366 367 private: 368 // Temporary directory for testing. 369 base::ScopedTempDir temp_dir_; 370 371 // Specifies the type of UI (if any) to show during installation and what 372 // user action to simulate. 373 enum InstallUIType { 374 INSTALL_UI_TYPE_NONE, 375 INSTALL_UI_TYPE_CANCEL, 376 INSTALL_UI_TYPE_NORMAL, 377 INSTALL_UI_TYPE_AUTO_CONFIRM, 378 }; 379 380 const Extension* InstallOrUpdateExtension(const std::string& id, 381 const base::FilePath& path, 382 InstallUIType ui_type, 383 int expected_change); 384 const Extension* InstallOrUpdateExtension( 385 const std::string& id, 386 const base::FilePath& path, 387 InstallUIType ui_type, 388 int expected_change, 389 Browser* browser, 390 Extension::InitFromValueFlags creation_flags); 391 const Extension* InstallOrUpdateExtension(const std::string& id, 392 const base::FilePath& path, 393 InstallUIType ui_type, 394 int expected_change, 395 Manifest::Location install_source); 396 const Extension* InstallOrUpdateExtension( 397 const std::string& id, 398 const base::FilePath& path, 399 InstallUIType ui_type, 400 int expected_change, 401 Manifest::Location install_source, 402 Browser* browser, 403 Extension::InitFromValueFlags creation_flags, 404 bool wait_for_idle, 405 bool grant_permissions); 406 407 // Make the current channel "dev" for the duration of the test. 408 ScopedCurrentChannel current_channel_; 409 410 // Disable external install UI. 411 FeatureSwitch::ScopedOverride override_prompt_for_external_extensions_; 412 413 #if defined(OS_WIN) 414 // Use mock shortcut directories to ensure app shortcuts are cleaned up. 415 base::ScopedPathOverride user_desktop_override_; 416 base::ScopedPathOverride common_desktop_override_; 417 base::ScopedPathOverride user_quick_launch_override_; 418 base::ScopedPathOverride start_menu_override_; 419 base::ScopedPathOverride common_start_menu_override_; 420 #endif 421 422 // The default profile to be used. 423 Profile* profile_; 424 425 // Cache cache implementation. 426 std::unique_ptr<ExtensionCacheFake> test_extension_cache_; 427 428 // An override so that chrome-extensions://<extension_id>/_test_resources/foo 429 // maps to chrome/test/data/extensions/foo. 430 ExtensionProtocolTestHandler test_protocol_handler_; 431 432 // Conditionally disable content verification. 433 std::unique_ptr<ScopedIgnoreContentVerifierForTest> 434 ignore_content_verification_; 435 436 // Conditionally disable install verification. 437 std::unique_ptr<ScopedInstallVerifierBypassForTest> 438 ignore_install_verification_; 439 440 // Used to disable CRX publisher signature checking. 441 SandboxedUnpacker::ScopedVerifierFormatOverrideForTest 442 verifier_format_override_; 443 444 ExtensionUpdater::ScopedSkipScheduledCheckForTest skip_scheduled_check_; 445 446 DISALLOW_COPY_AND_ASSIGN(ExtensionBrowserTest); 447 }; 448 449 } // namespace extensions 450 451 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_ 452