<commit_before>// 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.

#include <vector>

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
#include "chrome/browser/extensions/bundle_installer.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/gpu_feature_type.h"
#include "content/public/common/gpu_info.h"
#include "content/public/test/browser_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "ui/gl/gl_switches.h"

using content::GpuFeatureType;

namespace utils = extension_function_test_utils;

namespace extensions {

namespace {

class WebstoreInstallListener : public WebstoreInstaller::Delegate {
 public:
  WebstoreInstallListener()
      : received_failure_(false), received_success_(false), waiting_(false) {}

  virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE {
    received_success_ = true;
    id_ = id;

    if (waiting_) {
      waiting_ = false;
      MessageLoopForUI::current()->Quit();
    }
  }

  virtual void OnExtensionInstallFailure(
      const std::string& id,
      const std::string& error,
      WebstoreInstaller::FailureReason reason) OVERRIDE {
    received_failure_ = true;
    id_ = id;
    error_ = error;

    if (waiting_) {
      waiting_ = false;
      MessageLoopForUI::current()->Quit();
    }
  }

  void Wait() {
    if (received_success_ || received_failure_)
      return;

    waiting_ = true;
    content::RunMessageLoop();
  }
  bool received_success() const { return received_success_; }
  const std::string& id() const { return id_; }

 private:
  bool received_failure_;
  bool received_success_;
  bool waiting_;
  std::string id_;
  std::string error_;
};

}  // namespace

// A base class for tests below.
class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitchASCII(
        switches::kAppsGalleryURL,
        "http://www.example.com/files/extensions/api_test");
    command_line->AppendSwitchASCII(
        switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
  }

  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    // Start up the test server and get us ready for calling the install
    // API functions.
    host_resolver()->AddRule("www.example.com", "127.0.0.1");
    ASSERT_TRUE(test_server()->Start());
    ExtensionInstallUI::DisableFailureUIForTests();

    ASSERT_TRUE(tmp_.CreateUniqueTempDirUnderPath(test_data_dir_));
    ASSERT_TRUE(file_util::CreateDirectory(tmp_.path()));
    ASSERT_TRUE(file_util::CopyDirectory(
        test_data_dir_.AppendASCII("webstore_private"),
        tmp_.path(),
        true));
  }

 protected:
  // Returns a test server URL, but with host 'www.example.com' so it matches
  // the web store app's extent that we set up via command line flags.
  virtual GURL GetTestServerURL(const std::string& path) {
    std::string basename = tmp_.path().BaseName().MaybeAsASCII();
    GURL url = test_server()->GetURL(
        std::string("files/extensions/api_test/") +
        basename +
        "/webstore_private/" +
        path);

    // Replace the host with 'www.example.com' so it matches the web store
    // app's extent.
    GURL::Replacements replace_host;
    std::string host_str("www.example.com");
    replace_host.SetHostStr(host_str);

    return url.ReplaceComponents(replace_host);
  }

  // Navigates to |page| and runs the Extension API test there. Any downloads
  // of extensions will return the contents of |crx_file|.
  bool RunInstallTest(const std::string& page, const std::string& crx_file) {
    GURL crx_url = GetTestServerURL(crx_file);
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryUpdateURL, crx_url.spec());

    GURL page_url = GetTestServerURL(page);
    return RunPageTest(page_url.spec());
  }

  ExtensionService* service() {
    return browser()->profile()->GetExtensionService();
  }

  base::ScopedTempDir tmp_;
};

class ExtensionWebstorePrivateBundleTest
    : public ExtensionWebstorePrivateApiTest {
 public:
  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();

    // The test server needs to have already started, so setup the switch here
    // rather than in SetUpCommandLine.
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryDownloadURL,
        GetTestServerURL("bundle/%s.crx").spec());
  }

  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
    ExtensionWebstorePrivateApiTest::TearDownInProcessBrowserTestFixture();
    for (size_t i = 0; i < test_crx_.size(); ++i)
      ASSERT_TRUE(file_util::Delete(test_crx_[i], false));
  }

 protected:
  // Packs the |manifest| file into a CRX using |id|'s PEM key.
  void PackCRX(const std::string& id, const std::string& manifest) {
    // Move the extension to a temporary directory.
    base::ScopedTempDir tmp;
    ASSERT_TRUE(tmp.CreateUniqueTempDir());
    ASSERT_TRUE(file_util::CreateDirectory(tmp.path()));

    base::FilePath tmp_manifest = tmp.path().AppendASCII("manifest.json");
    base::FilePath data_path =
        test_data_dir_.AppendASCII("webstore_private/bundle");
    base::FilePath manifest_path = data_path.AppendASCII(manifest);

    ASSERT_TRUE(file_util::PathExists(manifest_path));
    ASSERT_TRUE(file_util::CopyFile(manifest_path, tmp_manifest));

    PackCRX(id, tmp.path());
  }

  // Packs the extension at |ext_path| using |id|'s PEM key.
  void PackCRX(const std::string& id, const base::FilePath& ext_path) {
    base::FilePath data_path =
        tmp_.path().AppendASCII("webstore_private/bundle");
    base::FilePath pem_path = data_path.AppendASCII(id + ".pem");
    base::FilePath crx_path = data_path.AppendASCII(id + ".crx");
    base::FilePath destination = PackExtensionWithOptions(
        ext_path, crx_path, pem_path, base::FilePath());

    ASSERT_FALSE(destination.empty());
    ASSERT_EQ(destination, crx_path);

    test_crx_.push_back(destination);
  }

  // Creates an invalid CRX.
  void PackInvalidCRX(const std::string& id) {
    base::FilePath contents = test_data_dir_
        .AppendASCII("webstore_private")
        .AppendASCII("install_bundle_invalid.html");
    base::FilePath crx_path = test_data_dir_
        .AppendASCII("webstore_private/bundle")
        .AppendASCII(id + ".crx");

    ASSERT_TRUE(file_util::CopyFile(contents, crx_path));

    test_crx_.push_back(crx_path);
  }

 private:
  std::vector<base::FilePath> test_crx_;
};

class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    // We need to launch GPU process to decide if WebGL is allowed.
    // Run it on top of osmesa to avoid bot driver issues.
#if !defined(OS_MACOSX)
    CHECK(test_launcher_utils::OverrideGLImplementation(
        command_line, gfx::kGLImplementationOSMesaName)) <<
        "kUseGL must not be set multiple times!";
#endif
  }

 protected:
  void RunTest(bool webgl_allowed) {
    static const char kEmptyArgs[] = "[]";
    static const char kWebGLStatusAllowed[] = "webgl_allowed";
    static const char kWebGLStatusBlocked[] = "webgl_blocked";
    scoped_refptr<GetWebGLStatusFunction> function =
        new GetWebGLStatusFunction();
    scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
            function.get(), kEmptyArgs, browser()));
    ASSERT_TRUE(result);
    EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
    std::string webgl_status = "";
    EXPECT_TRUE(result->GetAsString(&webgl_status));
    EXPECT_STREQ(webgl_allowed ? kWebGLStatusAllowed : kWebGLStatusBlocked,
                 webgl_status.c_str());
  }
};

// Test cases for webstore origin frame blocking.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       FrameWebstorePageBlocked) {
  content::WebContents* contents =
      browser()->tab_strip_model()->GetActiveWebContents();
  string16 expected_title = UTF8ToUTF16("PASS: about:blank");
  string16 failure_title = UTF8ToUTF16("FAIL");
  content::TitleWatcher watcher(contents, expected_title);
  watcher.AlsoWaitForTitle(failure_title);
  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webstore_private/noframe.html");
  ui_test_utils::NavigateToURL(browser(), url);
  string16 final_title = watcher.WaitAndGetTitle();
  EXPECT_EQ(expected_title, final_title);
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       FrameErrorPageBlocked) {<commit_msg>Temporarily disable 'X-Frame-Options' tests, as the behavior is changing.<commit_after>// 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.

#include <vector>

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
#include "chrome/browser/extensions/bundle_installer.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/gpu_feature_type.h"
#include "content/public/common/gpu_info.h"
#include "content/public/test/browser_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "ui/gl/gl_switches.h"

using content::GpuFeatureType;

namespace utils = extension_function_test_utils;

namespace extensions {

namespace {

class WebstoreInstallListener : public WebstoreInstaller::Delegate {
 public:
  WebstoreInstallListener()
      : received_failure_(false), received_success_(false), waiting_(false) {}

  virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE {
    received_success_ = true;
    id_ = id;

    if (waiting_) {
      waiting_ = false;
      MessageLoopForUI::current()->Quit();
    }
  }

  virtual void OnExtensionInstallFailure(
      const std::string& id,
      const std::string& error,
      WebstoreInstaller::FailureReason reason) OVERRIDE {
    received_failure_ = true;
    id_ = id;
    error_ = error;

    if (waiting_) {
      waiting_ = false;
      MessageLoopForUI::current()->Quit();
    }
  }

  void Wait() {
    if (received_success_ || received_failure_)
      return;

    waiting_ = true;
    content::RunMessageLoop();
  }
  bool received_success() const { return received_success_; }
  const std::string& id() const { return id_; }

 private:
  bool received_failure_;
  bool received_success_;
  bool waiting_;
  std::string id_;
  std::string error_;
};

}  // namespace

// A base class for tests below.
class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitchASCII(
        switches::kAppsGalleryURL,
        "http://www.example.com/files/extensions/api_test");
    command_line->AppendSwitchASCII(
        switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
  }

  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    // Start up the test server and get us ready for calling the install
    // API functions.
    host_resolver()->AddRule("www.example.com", "127.0.0.1");
    ASSERT_TRUE(test_server()->Start());
    ExtensionInstallUI::DisableFailureUIForTests();

    ASSERT_TRUE(tmp_.CreateUniqueTempDirUnderPath(test_data_dir_));
    ASSERT_TRUE(file_util::CreateDirectory(tmp_.path()));
    ASSERT_TRUE(file_util::CopyDirectory(
        test_data_dir_.AppendASCII("webstore_private"),
        tmp_.path(),
        true));
  }

 protected:
  // Returns a test server URL, but with host 'www.example.com' so it matches
  // the web store app's extent that we set up via command line flags.
  virtual GURL GetTestServerURL(const std::string& path) {
    std::string basename = tmp_.path().BaseName().MaybeAsASCII();
    GURL url = test_server()->GetURL(
        std::string("files/extensions/api_test/") +
        basename +
        "/webstore_private/" +
        path);

    // Replace the host with 'www.example.com' so it matches the web store
    // app's extent.
    GURL::Replacements replace_host;
    std::string host_str("www.example.com");
    replace_host.SetHostStr(host_str);

    return url.ReplaceComponents(replace_host);
  }

  // Navigates to |page| and runs the Extension API test there. Any downloads
  // of extensions will return the contents of |crx_file|.
  bool RunInstallTest(const std::string& page, const std::string& crx_file) {
    GURL crx_url = GetTestServerURL(crx_file);
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryUpdateURL, crx_url.spec());

    GURL page_url = GetTestServerURL(page);
    return RunPageTest(page_url.spec());
  }

  ExtensionService* service() {
    return browser()->profile()->GetExtensionService();
  }

  base::ScopedTempDir tmp_;
};

class ExtensionWebstorePrivateBundleTest
    : public ExtensionWebstorePrivateApiTest {
 public:
  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();

    // The test server needs to have already started, so setup the switch here
    // rather than in SetUpCommandLine.
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryDownloadURL,
        GetTestServerURL("bundle/%s.crx").spec());
  }

  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
    ExtensionWebstorePrivateApiTest::TearDownInProcessBrowserTestFixture();
    for (size_t i = 0; i < test_crx_.size(); ++i)
      ASSERT_TRUE(file_util::Delete(test_crx_[i], false));
  }

 protected:
  // Packs the |manifest| file into a CRX using |id|'s PEM key.
  void PackCRX(const std::string& id, const std::string& manifest) {
    // Move the extension to a temporary directory.
    base::ScopedTempDir tmp;
    ASSERT_TRUE(tmp.CreateUniqueTempDir());
    ASSERT_TRUE(file_util::CreateDirectory(tmp.path()));

    base::FilePath tmp_manifest = tmp.path().AppendASCII("manifest.json");
    base::FilePath data_path =
        test_data_dir_.AppendASCII("webstore_private/bundle");
    base::FilePath manifest_path = data_path.AppendASCII(manifest);

    ASSERT_TRUE(file_util::PathExists(manifest_path));
    ASSERT_TRUE(file_util::CopyFile(manifest_path, tmp_manifest));

    PackCRX(id, tmp.path());
  }

  // Packs the extension at |ext_path| using |id|'s PEM key.
  void PackCRX(const std::string& id, const base::FilePath& ext_path) {
    base::FilePath data_path =
        tmp_.path().AppendASCII("webstore_private/bundle");
    base::FilePath pem_path = data_path.AppendASCII(id + ".pem");
    base::FilePath crx_path = data_path.AppendASCII(id + ".crx");
    base::FilePath destination = PackExtensionWithOptions(
        ext_path, crx_path, pem_path, base::FilePath());

    ASSERT_FALSE(destination.empty());
    ASSERT_EQ(destination, crx_path);

    test_crx_.push_back(destination);
  }

  // Creates an invalid CRX.
  void PackInvalidCRX(const std::string& id) {
    base::FilePath contents = test_data_dir_
        .AppendASCII("webstore_private")
        .AppendASCII("install_bundle_invalid.html");
    base::FilePath crx_path = test_data_dir_
        .AppendASCII("webstore_private/bundle")
        .AppendASCII(id + ".crx");

    ASSERT_TRUE(file_util::CopyFile(contents, crx_path));

    test_crx_.push_back(crx_path);
  }

 private:
  std::vector<base::FilePath> test_crx_;
};

class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    // We need to launch GPU process to decide if WebGL is allowed.
    // Run it on top of osmesa to avoid bot driver issues.
#if !defined(OS_MACOSX)
    CHECK(test_launcher_utils::OverrideGLImplementation(
        command_line, gfx::kGLImplementationOSMesaName)) <<
        "kUseGL must not be set multiple times!";
#endif
  }

 protected:
  void RunTest(bool webgl_allowed) {
    static const char kEmptyArgs[] = "[]";
    static const char kWebGLStatusAllowed[] = "webgl_allowed";
    static const char kWebGLStatusBlocked[] = "webgl_blocked";
    scoped_refptr<GetWebGLStatusFunction> function =
        new GetWebGLStatusFunction();
    scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
            function.get(), kEmptyArgs, browser()));
    ASSERT_TRUE(result);
    EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
    std::string webgl_status = "";
    EXPECT_TRUE(result->GetAsString(&webgl_status));
    EXPECT_STREQ(webgl_allowed ? kWebGLStatusAllowed : kWebGLStatusBlocked,
                 webgl_status.c_str());
  }
};

// Test cases for webstore origin frame blocking.
// TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
// Chromium, see crbug.com/226018.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       DISABLED_FrameWebstorePageBlocked) {
  content::WebContents* contents =
      browser()->tab_strip_model()->GetActiveWebContents();
  string16 expected_title = UTF8ToUTF16("PASS: about:blank");
  string16 failure_title = UTF8ToUTF16("FAIL");
  content::TitleWatcher watcher(contents, expected_title);
  watcher.AlsoWaitForTitle(failure_title);
  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webstore_private/noframe.html");
  ui_test_utils::NavigateToURL(browser(), url);
  string16 final_title = watcher.WaitAndGetTitle();
  EXPECT_EQ(expected_title, final_title);
}

// TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
// Chromium, see crbug.com/226018.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       DISABLED_FrameErrorPageBlocked) {
{'fraction_non_alphanumeric': 0.11437216338880483, 'fraction_numerical': 0.002924861321230459, 'mean_word_length': 4.49031007751938, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 10, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5529602', 'n_tokens_mistral': 6204, 'n_tokens_neox': 6065, 'n_words': 1228}