C++程序  |  391行  |  14.1 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_

#include <string>

#include "base/command_line.h"

#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "chrome/browser/extensions/extension_test_notification_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/features/feature_channel.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest.h"

class ExtensionService;
class Profile;

namespace extensions {
class ExtensionCacheFake;
class ExtensionSet;
class ProcessManager;
}

// Base class for extension browser tests. Provides utilities for loading,
// unloading, and installing extensions.
class ExtensionBrowserTest : virtual public InProcessBrowserTest {
 protected:
  // Flags used to configure how the tests are run.
  enum Flags {
    kFlagNone = 0,

    // Allow the extension to run in incognito mode.
    kFlagEnableIncognito = 1 << 0,

    // Allow file access for the extension.
    kFlagEnableFileAccess = 1 << 1,

    // Don't fail when the loaded manifest has warnings (should only be used
    // when testing deprecated features).
    kFlagIgnoreManifestWarnings = 1 << 2,

    // Allow older manifest versions (typically these can't be loaded - we allow
    // them for testing).
    kFlagAllowOldManifestVersions = 1 << 3,
  };

  ExtensionBrowserTest();
  virtual ~ExtensionBrowserTest();

  // Useful accessors.
  ExtensionService* extension_service() {
    return extensions::ExtensionSystem::Get(profile())->extension_service();
  }

  const std::string& last_loaded_extension_id() {
    return observer_->last_loaded_extension_id();
  }

  // Get the profile to use.
  virtual Profile* profile();

  static const extensions::Extension* GetExtensionByPath(
      const extensions::ExtensionSet* extensions, const base::FilePath& path);

  // InProcessBrowserTest
  virtual void SetUp() OVERRIDE;
  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
  virtual void SetUpOnMainThread() OVERRIDE;

  const extensions::Extension* LoadExtension(const base::FilePath& path);

  // Load extension and enable it in incognito mode.
  const extensions::Extension* LoadExtensionIncognito(
      const base::FilePath& path);

  // Load extension from the |path| folder. |flags| is bit mask of values from
  // |Flags| enum.
  const extensions::Extension* LoadExtensionWithFlags(
      const base::FilePath& path, int flags);

  // Same as above, but sets the installation parameter to the extension
  // preferences.
  const extensions::Extension* LoadExtensionWithInstallParam(
      const base::FilePath& path,
      int flags,
      const std::string& install_param);

  // Loads unpacked extension from |path| with manifest |manifest_relative_path|
  // and imitates that it is a component extension.
  // |manifest_relative_path| is relative to |path|.
  const extensions::Extension* LoadExtensionAsComponentWithManifest(
      const base::FilePath& path,
      const base::FilePath::CharType* manifest_relative_path);

  // Loads unpacked extension from |path| and imitates that it is a component
  // extension. Equivalent to
  // LoadExtensionAsComponentWithManifest(path, extensions::kManifestFilename).
  const extensions::Extension* LoadExtensionAsComponent(
      const base::FilePath& path);

  // Pack the extension in |dir_path| into a crx file and return its path.
  // Return an empty FilePath if there were errors.
  base::FilePath PackExtension(const base::FilePath& dir_path);

  // Pack the extension in |dir_path| into a crx file at |crx_path|, using the
  // key |pem_path|. If |pem_path| does not exist, create a new key at
  // |pem_out_path|.
  // Return the path to the crx file, or an empty FilePath if there were errors.
  base::FilePath PackExtensionWithOptions(const base::FilePath& dir_path,
                                          const base::FilePath& crx_path,
                                          const base::FilePath& pem_path,
                                          const base::FilePath& pem_out_path);

  // |expected_change| indicates how many extensions should be installed (or
  // disabled, if negative).
  // 1 means you expect a new install, 0 means you expect an upgrade, -1 means
  // you expect a failed upgrade.
  const extensions::Extension* InstallExtension(const base::FilePath& path,
                                                int expected_change) {
    return InstallOrUpdateExtension(
        std::string(), path, INSTALL_UI_TYPE_NONE, expected_change);
  }

  // Same as above, but an install source other than Manifest::INTERNAL can be
  // specified.
  const extensions::Extension* InstallExtension(
      const base::FilePath& path,
      int expected_change,
      extensions::Manifest::Location install_source) {
    return InstallOrUpdateExtension(std::string(),
                                    path,
                                    INSTALL_UI_TYPE_NONE,
                                    expected_change,
                                    install_source);
  }

  // Installs extension as if it came from the Chrome Webstore.
  const extensions::Extension* InstallExtensionFromWebstore(
      const base::FilePath& path, int expected_change);

  // Same as above but passes an id to CrxInstaller and does not allow a
  // privilege increase.
  const extensions::Extension* UpdateExtension(const std::string& id,
                                               const base::FilePath& path,
                                               int expected_change) {
    return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE,
                                    expected_change);
  }

  // Same as UpdateExtension but waits for the extension to be idle first.
  const extensions::Extension* UpdateExtensionWaitForIdle(
      const std::string& id, const base::FilePath& path, int expected_change);

  // Same as |InstallExtension| but with the normal extension UI showing up
  // (for e.g. info bar on success).
  const extensions::Extension* InstallExtensionWithUI(
      const base::FilePath& path,
      int expected_change) {
    return InstallOrUpdateExtension(
        std::string(), path, INSTALL_UI_TYPE_NORMAL, expected_change);
  }

  const extensions::Extension* InstallExtensionWithUIAutoConfirm(
      const base::FilePath& path,
      int expected_change,
      Browser* browser) {
    return InstallOrUpdateExtension(std::string(),
                                    path,
                                    INSTALL_UI_TYPE_AUTO_CONFIRM,
                                    expected_change,
                                    browser,
                                    extensions::Extension::NO_FLAGS);
  }

  const extensions::Extension* InstallExtensionWithSourceAndFlags(
      const base::FilePath& path,
      int expected_change,
      extensions::Manifest::Location install_source,
      extensions::Extension::InitFromValueFlags creation_flags) {
    return InstallOrUpdateExtension(std::string(),
                                    path,
                                    INSTALL_UI_TYPE_NONE,
                                    expected_change,
                                    install_source,
                                    browser(),
                                    creation_flags,
                                    false,
                                    false);
  }

  const extensions::Extension* InstallEphemeralAppWithSourceAndFlags(
      const base::FilePath& path,
      int expected_change,
      extensions::Manifest::Location install_source,
      extensions::Extension::InitFromValueFlags creation_flags) {
    return InstallOrUpdateExtension(std::string(),
                                    path,
                                    INSTALL_UI_TYPE_NONE,
                                    expected_change,
                                    install_source,
                                    browser(),
                                    creation_flags,
                                    false,
                                    true);
  }

  // Begins install process but simulates a user cancel.
  const extensions::Extension* StartInstallButCancel(
      const base::FilePath& path) {
    return InstallOrUpdateExtension(
        std::string(), path, INSTALL_UI_TYPE_CANCEL, 0);
  }

  void ReloadExtension(const std::string extension_id);

  void UnloadExtension(const std::string& extension_id);

  void UninstallExtension(const std::string& extension_id);

  void DisableExtension(const std::string& extension_id);

  void EnableExtension(const std::string& extension_id);

  // Wait for the total number of page actions to change to |count|.
  bool WaitForPageActionCountChangeTo(int count) {
    return observer_->WaitForPageActionCountChangeTo(count);
  }

  // Wait for the number of visible page actions to change to |count|.
  bool WaitForPageActionVisibilityChangeTo(int count) {
    return observer_->WaitForPageActionVisibilityChangeTo(count);
  }

  // Waits until an extension is installed and loaded. Returns true if an
  // install happened before timeout.
  bool WaitForExtensionInstall() {
    return observer_->WaitForExtensionInstall();
  }

  // Wait for an extension install error to be raised. Returns true if an
  // error was raised.
  bool WaitForExtensionInstallError() {
    return observer_->WaitForExtensionInstallError();
  }

  // Waits until an extension is loaded and all view have loaded.
  void WaitForExtensionAndViewLoad() {
    return observer_->WaitForExtensionAndViewLoad();
  }

  // Waits until an extension is loaded.
  void WaitForExtensionLoad() {
    return observer_->WaitForExtensionLoad();
  }

  // Waits for an extension load error. Returns true if the error really
  // happened.
  bool WaitForExtensionLoadError() {
    return observer_->WaitForExtensionLoadError();
  }

  // Wait for the specified extension to crash. Returns true if it really
  // crashed.
  bool WaitForExtensionCrash(const std::string& extension_id) {
    return observer_->WaitForExtensionCrash(extension_id);
  }

  // Wait for the crx installer to be done. Returns true if it really is done.
  bool WaitForCrxInstallerDone() {
    return observer_->WaitForCrxInstallerDone();
  }

  // Wait for all extension views to load.
  bool WaitForExtensionViewsToLoad() {
    return observer_->WaitForExtensionViewsToLoad();
  }

  // Simulates a page calling window.open on an URL and waits for the
  // navigation.
  void OpenWindow(content::WebContents* contents,
                  const GURL& url,
                  bool newtab_process_should_equal_opener,
                  content::WebContents** newtab_result);

  // Simulates a page navigating itself to an URL and waits for the
  // navigation.
  void NavigateInRenderer(content::WebContents* contents, const GURL& url);

  // Looks for an ExtensionHost whose URL has the given path component
  // (including leading slash).  Also verifies that the expected number of hosts
  // are loaded.
  extensions::ExtensionHost* FindHostWithPath(
      extensions::ProcessManager* manager,
      const std::string& path,
      int expected_hosts);

  // Returns
  // extensions::browsertest_util::ExecuteScriptInBackgroundPage(profile(),
  // extension_id, script).
  std::string ExecuteScriptInBackgroundPage(const std::string& extension_id,
                                            const std::string& script);

  // Returns
  // extensions::browsertest_util::ExecuteScriptInBackgroundPageNoWait(
  // profile(), extension_id, script).
  bool ExecuteScriptInBackgroundPageNoWait(const std::string& extension_id,
                                           const std::string& script);

  bool loaded_;
  bool installed_;

#if defined(OS_CHROMEOS)
  // True if the command line should be tweaked as if ChromeOS user is
  // already logged in.
  bool set_chromeos_user_;
#endif

  // test_data/extensions.
  base::FilePath test_data_dir_;

  scoped_ptr<ExtensionTestNotificationObserver> observer_;

 private:
  // Temporary directory for testing.
  base::ScopedTempDir temp_dir_;

  // Specifies the type of UI (if any) to show during installation and what
  // user action to simulate.
  enum InstallUIType {
    INSTALL_UI_TYPE_NONE,
    INSTALL_UI_TYPE_CANCEL,
    INSTALL_UI_TYPE_NORMAL,
    INSTALL_UI_TYPE_AUTO_CONFIRM,
  };

  const extensions::Extension* InstallOrUpdateExtension(
      const std::string& id,
      const base::FilePath& path,
      InstallUIType ui_type,
      int expected_change);
  const extensions::Extension* InstallOrUpdateExtension(
      const std::string& id,
      const base::FilePath& path,
      InstallUIType ui_type,
      int expected_change,
      Browser* browser,
      extensions::Extension::InitFromValueFlags creation_flags);
  const extensions::Extension* InstallOrUpdateExtension(
      const std::string& id,
      const base::FilePath& path,
      InstallUIType ui_type,
      int expected_change,
      extensions::Manifest::Location install_source);
  const extensions::Extension* InstallOrUpdateExtension(
      const std::string& id,
      const base::FilePath& path,
      InstallUIType ui_type,
      int expected_change,
      extensions::Manifest::Location install_source,
      Browser* browser,
      extensions::Extension::InitFromValueFlags creation_flags,
      bool wait_for_idle,
      bool is_ephemeral);

  // Make the current channel "dev" for the duration of the test.
  extensions::ScopedCurrentChannel current_channel_;

  // Disable external install UI.
  extensions::FeatureSwitch::ScopedOverride
      override_prompt_for_external_extensions_;

  // The default profile to be used.
  Profile* profile_;

  // Cache cache implementation.
  scoped_ptr<extensions::ExtensionCacheFake> test_extension_cache_;
};

#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_