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