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