• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "chrome/browser/extensions/extension_test_notification_observer.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/common/extensions/features/feature_channel.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "content/public/browser/web_contents.h"
20 #include "extensions/browser/extension_host.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/feature_switch.h"
24 #include "extensions/common/manifest.h"
25 
26 class ExtensionService;
27 class Profile;
28 
29 namespace extensions {
30 class ExtensionCacheFake;
31 class ExtensionSet;
32 class ProcessManager;
33 }
34 
35 // Base class for extension browser tests. Provides utilities for loading,
36 // unloading, and installing extensions.
37 class ExtensionBrowserTest : virtual public InProcessBrowserTest {
38  protected:
39   // Flags used to configure how the tests are run.
40   enum Flags {
41     kFlagNone = 0,
42 
43     // Allow the extension to run in incognito mode.
44     kFlagEnableIncognito = 1 << 0,
45 
46     // Allow file access for the extension.
47     kFlagEnableFileAccess = 1 << 1,
48 
49     // Don't fail when the loaded manifest has warnings (should only be used
50     // when testing deprecated features).
51     kFlagIgnoreManifestWarnings = 1 << 2,
52 
53     // Allow older manifest versions (typically these can't be loaded - we allow
54     // them for testing).
55     kFlagAllowOldManifestVersions = 1 << 3,
56   };
57 
58   ExtensionBrowserTest();
59   virtual ~ExtensionBrowserTest();
60 
61   // Useful accessors.
extension_service()62   ExtensionService* extension_service() {
63     return extensions::ExtensionSystem::Get(profile())->extension_service();
64   }
65 
last_loaded_extension_id()66   const std::string& last_loaded_extension_id() {
67     return observer_->last_loaded_extension_id();
68   }
69 
70   // Get the profile to use.
71   virtual Profile* profile();
72 
73   static const extensions::Extension* GetExtensionByPath(
74       const extensions::ExtensionSet* extensions, const base::FilePath& path);
75 
76   // InProcessBrowserTest
77   virtual void SetUp() OVERRIDE;
78   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
79   virtual void SetUpOnMainThread() OVERRIDE;
80 
81   const extensions::Extension* LoadExtension(const base::FilePath& path);
82 
83   // Load extension and enable it in incognito mode.
84   const extensions::Extension* LoadExtensionIncognito(
85       const base::FilePath& path);
86 
87   // Load extension from the |path| folder. |flags| is bit mask of values from
88   // |Flags| enum.
89   const extensions::Extension* LoadExtensionWithFlags(
90       const base::FilePath& path, int flags);
91 
92   // Same as above, but sets the installation parameter to the extension
93   // preferences.
94   const extensions::Extension* LoadExtensionWithInstallParam(
95       const base::FilePath& path,
96       int flags,
97       const std::string& install_param);
98 
99   // Loads unpacked extension from |path| with manifest |manifest_relative_path|
100   // and imitates that it is a component extension.
101   // |manifest_relative_path| is relative to |path|.
102   const extensions::Extension* LoadExtensionAsComponentWithManifest(
103       const base::FilePath& path,
104       const base::FilePath::CharType* manifest_relative_path);
105 
106   // Loads unpacked extension from |path| and imitates that it is a component
107   // extension. Equivalent to
108   // LoadExtensionAsComponentWithManifest(path, extensions::kManifestFilename).
109   const extensions::Extension* LoadExtensionAsComponent(
110       const base::FilePath& path);
111 
112   // Pack the extension in |dir_path| into a crx file and return its path.
113   // Return an empty FilePath if there were errors.
114   base::FilePath PackExtension(const base::FilePath& dir_path);
115 
116   // Pack the extension in |dir_path| into a crx file at |crx_path|, using the
117   // key |pem_path|. If |pem_path| does not exist, create a new key at
118   // |pem_out_path|.
119   // Return the path to the crx file, or an empty FilePath if there were errors.
120   base::FilePath PackExtensionWithOptions(const base::FilePath& dir_path,
121                                           const base::FilePath& crx_path,
122                                           const base::FilePath& pem_path,
123                                           const base::FilePath& pem_out_path);
124 
125   // |expected_change| indicates how many extensions should be installed (or
126   // disabled, if negative).
127   // 1 means you expect a new install, 0 means you expect an upgrade, -1 means
128   // you expect a failed upgrade.
InstallExtension(const base::FilePath & path,int expected_change)129   const extensions::Extension* InstallExtension(const base::FilePath& path,
130                                                 int expected_change) {
131     return InstallOrUpdateExtension(
132         std::string(), path, INSTALL_UI_TYPE_NONE, expected_change);
133   }
134 
135   // Same as above, but an install source other than Manifest::INTERNAL can be
136   // specified.
InstallExtension(const base::FilePath & path,int expected_change,extensions::Manifest::Location install_source)137   const extensions::Extension* InstallExtension(
138       const base::FilePath& path,
139       int expected_change,
140       extensions::Manifest::Location install_source) {
141     return InstallOrUpdateExtension(std::string(),
142                                     path,
143                                     INSTALL_UI_TYPE_NONE,
144                                     expected_change,
145                                     install_source);
146   }
147 
148   // Installs extension as if it came from the Chrome Webstore.
149   const extensions::Extension* InstallExtensionFromWebstore(
150       const base::FilePath& path, int expected_change);
151 
152   // Same as above but passes an id to CrxInstaller and does not allow a
153   // privilege increase.
UpdateExtension(const std::string & id,const base::FilePath & path,int expected_change)154   const extensions::Extension* UpdateExtension(const std::string& id,
155                                                const base::FilePath& path,
156                                                int expected_change) {
157     return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE,
158                                     expected_change);
159   }
160 
161   // Same as UpdateExtension but waits for the extension to be idle first.
162   const extensions::Extension* UpdateExtensionWaitForIdle(
163       const std::string& id, const base::FilePath& path, int expected_change);
164 
165   // Same as |InstallExtension| but with the normal extension UI showing up
166   // (for e.g. info bar on success).
InstallExtensionWithUI(const base::FilePath & path,int expected_change)167   const extensions::Extension* InstallExtensionWithUI(
168       const base::FilePath& path,
169       int expected_change) {
170     return InstallOrUpdateExtension(
171         std::string(), path, INSTALL_UI_TYPE_NORMAL, expected_change);
172   }
173 
InstallExtensionWithUIAutoConfirm(const base::FilePath & path,int expected_change,Browser * browser)174   const extensions::Extension* InstallExtensionWithUIAutoConfirm(
175       const base::FilePath& path,
176       int expected_change,
177       Browser* browser) {
178     return InstallOrUpdateExtension(std::string(),
179                                     path,
180                                     INSTALL_UI_TYPE_AUTO_CONFIRM,
181                                     expected_change,
182                                     browser,
183                                     extensions::Extension::NO_FLAGS);
184   }
185 
InstallExtensionWithSourceAndFlags(const base::FilePath & path,int expected_change,extensions::Manifest::Location install_source,extensions::Extension::InitFromValueFlags creation_flags)186   const extensions::Extension* InstallExtensionWithSourceAndFlags(
187       const base::FilePath& path,
188       int expected_change,
189       extensions::Manifest::Location install_source,
190       extensions::Extension::InitFromValueFlags creation_flags) {
191     return InstallOrUpdateExtension(std::string(),
192                                     path,
193                                     INSTALL_UI_TYPE_NONE,
194                                     expected_change,
195                                     install_source,
196                                     browser(),
197                                     creation_flags,
198                                     false,
199                                     false);
200   }
201 
InstallEphemeralAppWithSourceAndFlags(const base::FilePath & path,int expected_change,extensions::Manifest::Location install_source,extensions::Extension::InitFromValueFlags creation_flags)202   const extensions::Extension* InstallEphemeralAppWithSourceAndFlags(
203       const base::FilePath& path,
204       int expected_change,
205       extensions::Manifest::Location install_source,
206       extensions::Extension::InitFromValueFlags creation_flags) {
207     return InstallOrUpdateExtension(std::string(),
208                                     path,
209                                     INSTALL_UI_TYPE_NONE,
210                                     expected_change,
211                                     install_source,
212                                     browser(),
213                                     creation_flags,
214                                     false,
215                                     true);
216   }
217 
218   // Begins install process but simulates a user cancel.
StartInstallButCancel(const base::FilePath & path)219   const extensions::Extension* StartInstallButCancel(
220       const base::FilePath& path) {
221     return InstallOrUpdateExtension(
222         std::string(), path, INSTALL_UI_TYPE_CANCEL, 0);
223   }
224 
225   void ReloadExtension(const std::string extension_id);
226 
227   void UnloadExtension(const std::string& extension_id);
228 
229   void UninstallExtension(const std::string& extension_id);
230 
231   void DisableExtension(const std::string& extension_id);
232 
233   void EnableExtension(const std::string& extension_id);
234 
235   // Wait for the total number of page actions to change to |count|.
WaitForPageActionCountChangeTo(int count)236   bool WaitForPageActionCountChangeTo(int count) {
237     return observer_->WaitForPageActionCountChangeTo(count);
238   }
239 
240   // Wait for the number of visible page actions to change to |count|.
WaitForPageActionVisibilityChangeTo(int count)241   bool WaitForPageActionVisibilityChangeTo(int count) {
242     return observer_->WaitForPageActionVisibilityChangeTo(count);
243   }
244 
245   // Waits until an extension is installed and loaded. Returns true if an
246   // install happened before timeout.
WaitForExtensionInstall()247   bool WaitForExtensionInstall() {
248     return observer_->WaitForExtensionInstall();
249   }
250 
251   // Wait for an extension install error to be raised. Returns true if an
252   // error was raised.
WaitForExtensionInstallError()253   bool WaitForExtensionInstallError() {
254     return observer_->WaitForExtensionInstallError();
255   }
256 
257   // Waits until an extension is loaded and all view have loaded.
WaitForExtensionAndViewLoad()258   void WaitForExtensionAndViewLoad() {
259     return observer_->WaitForExtensionAndViewLoad();
260   }
261 
262   // Waits until an extension is loaded.
WaitForExtensionLoad()263   void WaitForExtensionLoad() {
264     return observer_->WaitForExtensionLoad();
265   }
266 
267   // Waits for an extension load error. Returns true if the error really
268   // happened.
WaitForExtensionLoadError()269   bool WaitForExtensionLoadError() {
270     return observer_->WaitForExtensionLoadError();
271   }
272 
273   // Wait for the specified extension to crash. Returns true if it really
274   // crashed.
WaitForExtensionCrash(const std::string & extension_id)275   bool WaitForExtensionCrash(const std::string& extension_id) {
276     return observer_->WaitForExtensionCrash(extension_id);
277   }
278 
279   // Wait for the crx installer to be done. Returns true if it really is done.
WaitForCrxInstallerDone()280   bool WaitForCrxInstallerDone() {
281     return observer_->WaitForCrxInstallerDone();
282   }
283 
284   // Wait for all extension views to load.
WaitForExtensionViewsToLoad()285   bool WaitForExtensionViewsToLoad() {
286     return observer_->WaitForExtensionViewsToLoad();
287   }
288 
289   // Simulates a page calling window.open on an URL and waits for the
290   // navigation.
291   void OpenWindow(content::WebContents* contents,
292                   const GURL& url,
293                   bool newtab_process_should_equal_opener,
294                   content::WebContents** newtab_result);
295 
296   // Simulates a page navigating itself to an URL and waits for the
297   // navigation.
298   void NavigateInRenderer(content::WebContents* contents, const GURL& url);
299 
300   // Looks for an ExtensionHost whose URL has the given path component
301   // (including leading slash).  Also verifies that the expected number of hosts
302   // are loaded.
303   extensions::ExtensionHost* FindHostWithPath(
304       extensions::ProcessManager* manager,
305       const std::string& path,
306       int expected_hosts);
307 
308   // Returns
309   // extensions::browsertest_util::ExecuteScriptInBackgroundPage(profile(),
310   // extension_id, script).
311   std::string ExecuteScriptInBackgroundPage(const std::string& extension_id,
312                                             const std::string& script);
313 
314   // Returns
315   // extensions::browsertest_util::ExecuteScriptInBackgroundPageNoWait(
316   // profile(), extension_id, script).
317   bool ExecuteScriptInBackgroundPageNoWait(const std::string& extension_id,
318                                            const std::string& script);
319 
320   bool loaded_;
321   bool installed_;
322 
323 #if defined(OS_CHROMEOS)
324   // True if the command line should be tweaked as if ChromeOS user is
325   // already logged in.
326   bool set_chromeos_user_;
327 #endif
328 
329   // test_data/extensions.
330   base::FilePath test_data_dir_;
331 
332   scoped_ptr<ExtensionTestNotificationObserver> observer_;
333 
334  private:
335   // Temporary directory for testing.
336   base::ScopedTempDir temp_dir_;
337 
338   // Specifies the type of UI (if any) to show during installation and what
339   // user action to simulate.
340   enum InstallUIType {
341     INSTALL_UI_TYPE_NONE,
342     INSTALL_UI_TYPE_CANCEL,
343     INSTALL_UI_TYPE_NORMAL,
344     INSTALL_UI_TYPE_AUTO_CONFIRM,
345   };
346 
347   const extensions::Extension* InstallOrUpdateExtension(
348       const std::string& id,
349       const base::FilePath& path,
350       InstallUIType ui_type,
351       int expected_change);
352   const extensions::Extension* InstallOrUpdateExtension(
353       const std::string& id,
354       const base::FilePath& path,
355       InstallUIType ui_type,
356       int expected_change,
357       Browser* browser,
358       extensions::Extension::InitFromValueFlags creation_flags);
359   const extensions::Extension* InstallOrUpdateExtension(
360       const std::string& id,
361       const base::FilePath& path,
362       InstallUIType ui_type,
363       int expected_change,
364       extensions::Manifest::Location install_source);
365   const extensions::Extension* InstallOrUpdateExtension(
366       const std::string& id,
367       const base::FilePath& path,
368       InstallUIType ui_type,
369       int expected_change,
370       extensions::Manifest::Location install_source,
371       Browser* browser,
372       extensions::Extension::InitFromValueFlags creation_flags,
373       bool wait_for_idle,
374       bool is_ephemeral);
375 
376   // Make the current channel "dev" for the duration of the test.
377   extensions::ScopedCurrentChannel current_channel_;
378 
379   // Disable external install UI.
380   extensions::FeatureSwitch::ScopedOverride
381       override_prompt_for_external_extensions_;
382 
383   // The default profile to be used.
384   Profile* profile_;
385 
386   // Cache cache implementation.
387   scoped_ptr<extensions::ExtensionCacheFake> test_extension_cache_;
388 };
389 
390 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_
391