content_verifier_browsertest.cc revision 010d83a9304c5a91596085d917d248abff47903a
145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved.
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Use of this source code is governed by a BSD-style license that can be
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// found in the LICENSE file.
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "base/scoped_observer.h"
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "chrome/browser/extensions/extension_browsertest.h"
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "content/public/test/test_utils.h"
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "extensions/browser/content_verify_job.h"
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "extensions/browser/extension_prefs.h"
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "extensions/browser/extension_registry.h"
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "extensions/browser/extension_registry_observer.h"
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "extensions/common/switches.h"
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgnamespace extensions {
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgnamespace {
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Helper for observing extension unloads.
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgclass UnloadObserver : public ExtensionRegistryObserver {
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org public:
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  explicit UnloadObserver(ExtensionRegistry* registry) : observer_(this) {
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    observer_.Add(registry);
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual ~UnloadObserver() {}
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  void WaitForUnload(const ExtensionId& id) {
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (ContainsKey(observed_, id))
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      return;
2945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ASSERT_TRUE(loop_runner_.get() == NULL);
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    awaited_id_ = id;
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    loop_runner_ = new content::MessageLoopRunner();
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    loop_runner_->Run();
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual void OnExtensionUnloaded(
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      content::BrowserContext* browser_context,
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      const Extension* extension,
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      UnloadedExtensionInfo::Reason reason) OVERRIDE {
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    observed_.insert(extension->id());
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (awaited_id_ == extension->id())
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      loop_runner_->Quit();
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org private:
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  ExtensionId awaited_id_;
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  std::set<ExtensionId> observed_;
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  scoped_refptr<content::MessageLoopRunner> loop_runner_;
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  ScopedObserver<ExtensionRegistry, UnloadObserver> observer_;
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Helper for forcing ContentVerifyJob's to return an error.
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgclass JobDelegate : public ContentVerifyJob::TestDelegate {
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org public:
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  JobDelegate() : fail_next_read_(false), fail_next_done_(false) {}
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual ~JobDelegate() {}
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  void set_id(const ExtensionId& id) { id_ = id; }
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  void fail_next_read() { fail_next_read_ = true; }
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  void fail_next_done() { fail_next_done_ = true; }
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual ContentVerifyJob::FailureReason BytesRead(const ExtensionId& id,
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                    int count,
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                    const char* data) OVERRIDE {
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (id == id_ && fail_next_read_) {
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      fail_next_read_ = false;
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      return ContentVerifyJob::HASH_MISMATCH;
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return ContentVerifyJob::NONE;
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual ContentVerifyJob::FailureReason DoneReading(
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      const ExtensionId& id) OVERRIDE {
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (id == id_ && fail_next_done_) {
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      fail_next_done_ = false;
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org      return ContentVerifyJob::HASH_MISMATCH;
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return ContentVerifyJob::NONE;
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org private:
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  DISALLOW_COPY_AND_ASSIGN(JobDelegate);
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  ExtensionId id_;
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  bool fail_next_read_;
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  bool fail_next_done_;
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}  // namespace
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgclass ContentVerifierTest : public ExtensionBrowserTest {
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org public:
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  ContentVerifierTest() {}
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual ~ContentVerifierTest() {}
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ExtensionBrowserTest::SetUpCommandLine(command_line);
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    command_line->AppendSwitchASCII(
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switches::kExtensionContentVerification,
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switches::kExtensionContentVerificationEnforce);
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  // Setup our unload observer and JobDelegate, and install a test extension.
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual void SetUpOnMainThread() OVERRIDE {
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ExtensionBrowserTest::SetUpOnMainThread();
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unload_observer_.reset(
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        new UnloadObserver(ExtensionRegistry::Get(profile())));
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const Extension* extension = InstallExtensionFromWebstore(
11045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        test_data_dir_.AppendASCII("content_verifier/v1.crx"), 1);
11145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ASSERT_TRUE(extension);
11245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    id_ = extension->id();
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    page_url_ = extension->GetResourceURL("page.html");
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    delegate_.set_id(id_);
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ContentVerifyJob::SetDelegateForTests(&delegate_);
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual void TearDownOnMainThread() OVERRIDE {
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ContentVerifyJob::SetDelegateForTests(NULL);
12045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ExtensionBrowserTest::TearDownOnMainThread();
12145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
12245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  virtual void OpenPageAndWaitForUnload() {
12445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    AddTabAtIndex(1, page_url_, content::PAGE_TRANSITION_LINK);
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unload_observer_->WaitForUnload(id_);
12645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int reasons = prefs->GetDisableReasons(id_);
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    EXPECT_TRUE(reasons & Extension::DISABLE_CORRUPTED);
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    // This needs to happen before the ExtensionRegistry gets deleted, which
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    // happens before TearDownOnMainThread is called.
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unload_observer_.reset();
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  }
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org protected:
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  JobDelegate delegate_;
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  scoped_ptr<UnloadObserver> unload_observer_;
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  ExtensionId id_;
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  GURL page_url_;
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgIN_PROC_BROWSER_TEST_F(ContentVerifierTest, FailOnRead) {
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  delegate_.fail_next_read();
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  OpenPageAndWaitForUnload();
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgIN_PROC_BROWSER_TEST_F(ContentVerifierTest, FailOnDone) {
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  delegate_.fail_next_done();
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org  OpenPageAndWaitForUnload();
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
152}  // namespace extensions
153