Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / content_verifier_browsertest.cc
bloba7b9ac8acf28c4b02be802f4f6e0ae78758c6c27
1 // Copyright 2014 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.
5 #include "base/scoped_observer.h"
6 #include "chrome/browser/extensions/extension_browsertest.h"
7 #include "chrome/common/chrome_switches.h"
8 #include "content/public/test/test_utils.h"
9 #include "extensions/browser/content_verify_job.h"
10 #include "extensions/browser/extension_prefs.h"
11 #include "extensions/browser/extension_registry.h"
12 #include "extensions/browser/extension_registry_observer.h"
14 namespace extensions {
16 namespace {
18 // Helper for observing extension unloads.
19 class UnloadObserver : public ExtensionRegistryObserver {
20 public:
21 explicit UnloadObserver(ExtensionRegistry* registry) : observer_(this) {
22 observer_.Add(registry);
24 ~UnloadObserver() override {}
26 void WaitForUnload(const ExtensionId& id) {
27 if (ContainsKey(observed_, id))
28 return;
30 ASSERT_TRUE(loop_runner_.get() == NULL);
31 awaited_id_ = id;
32 loop_runner_ = new content::MessageLoopRunner();
33 loop_runner_->Run();
36 void OnExtensionUnloaded(content::BrowserContext* browser_context,
37 const Extension* extension,
38 UnloadedExtensionInfo::Reason reason) override {
39 observed_.insert(extension->id());
40 if (awaited_id_ == extension->id())
41 loop_runner_->Quit();
44 private:
45 ExtensionId awaited_id_;
46 std::set<ExtensionId> observed_;
47 scoped_refptr<content::MessageLoopRunner> loop_runner_;
48 ScopedObserver<ExtensionRegistry, UnloadObserver> observer_;
51 // Helper for forcing ContentVerifyJob's to return an error.
52 class JobDelegate : public ContentVerifyJob::TestDelegate {
53 public:
54 JobDelegate() : fail_next_read_(false), fail_next_done_(false) {}
56 virtual ~JobDelegate() {}
58 void set_id(const ExtensionId& id) { id_ = id; }
59 void fail_next_read() { fail_next_read_ = true; }
60 void fail_next_done() { fail_next_done_ = true; }
62 ContentVerifyJob::FailureReason BytesRead(const ExtensionId& id,
63 int count,
64 const char* data) override {
65 if (id == id_ && fail_next_read_) {
66 fail_next_read_ = false;
67 return ContentVerifyJob::HASH_MISMATCH;
69 return ContentVerifyJob::NONE;
72 ContentVerifyJob::FailureReason DoneReading(const ExtensionId& id) override {
73 if (id == id_ && fail_next_done_) {
74 fail_next_done_ = false;
75 return ContentVerifyJob::HASH_MISMATCH;
77 return ContentVerifyJob::NONE;
80 private:
81 DISALLOW_COPY_AND_ASSIGN(JobDelegate);
83 ExtensionId id_;
84 bool fail_next_read_;
85 bool fail_next_done_;
88 class JobObserver : public ContentVerifyJob::TestObserver {
89 public:
90 JobObserver();
91 virtual ~JobObserver();
93 // Call this to add an expected job result.
94 void ExpectJobResult(const std::string& extension_id,
95 const base::FilePath& relative_path,
96 bool expected_to_fail);
98 // Wait to see expected jobs. Returns true if we saw all jobs finish as
99 // expected, or false if any job completed with non-expected success/failure
100 // status.
101 bool WaitForExpectedJobs();
103 // ContentVerifyJob::TestObserver interface
104 void JobStarted(const std::string& extension_id,
105 const base::FilePath& relative_path) override;
107 void JobFinished(const std::string& extension_id,
108 const base::FilePath& relative_path,
109 bool failed) override;
111 private:
112 typedef std::pair<std::string, base::FilePath> ExtensionFile;
113 typedef std::map<ExtensionFile, bool> ExpectedJobs;
114 ExpectedJobs expected_jobs_;
115 scoped_refptr<content::MessageLoopRunner> loop_runner_;
116 bool saw_expected_job_results_;
119 void JobObserver::ExpectJobResult(const std::string& extension_id,
120 const base::FilePath& relative_path,
121 bool expected_to_fail) {
122 expected_jobs_.insert(std::make_pair(
123 ExtensionFile(extension_id, relative_path), expected_to_fail));
126 JobObserver::JobObserver() : saw_expected_job_results_(false) {
129 JobObserver::~JobObserver() {
132 bool JobObserver::WaitForExpectedJobs() {
133 if (!expected_jobs_.empty()) {
134 loop_runner_ = new content::MessageLoopRunner();
135 loop_runner_->Run();
137 return saw_expected_job_results_;
140 void JobObserver::JobStarted(const std::string& extension_id,
141 const base::FilePath& relative_path) {
144 void JobObserver::JobFinished(const std::string& extension_id,
145 const base::FilePath& relative_path,
146 bool failed) {
147 ExpectedJobs::iterator i = expected_jobs_.find(ExtensionFile(
148 extension_id, relative_path.NormalizePathSeparatorsTo('/')));
149 if (i != expected_jobs_.end()) {
150 if (failed != i->second) {
151 saw_expected_job_results_ = false;
152 if (loop_runner_.get())
153 loop_runner_->Quit();
155 expected_jobs_.erase(i);
156 if (expected_jobs_.empty()) {
157 saw_expected_job_results_ = true;
158 if (loop_runner_.get())
159 loop_runner_->Quit();
164 } // namespace
166 class ContentVerifierTest : public ExtensionBrowserTest {
167 public:
168 ContentVerifierTest() {}
169 ~ContentVerifierTest() override {}
171 void SetUpCommandLine(base::CommandLine* command_line) override {
172 ExtensionBrowserTest::SetUpCommandLine(command_line);
173 command_line->AppendSwitchASCII(
174 switches::kExtensionContentVerification,
175 switches::kExtensionContentVerificationEnforce);
178 // Setup our unload observer and JobDelegate, and install a test extension.
179 void SetUpOnMainThread() override {
180 ExtensionBrowserTest::SetUpOnMainThread();
183 void TearDownOnMainThread() override {
184 ContentVerifyJob::SetDelegateForTests(NULL);
185 ContentVerifyJob::SetObserverForTests(NULL);
186 ExtensionBrowserTest::TearDownOnMainThread();
189 virtual void OpenPageAndWaitForUnload() {
190 unload_observer_.reset(
191 new UnloadObserver(ExtensionRegistry::Get(profile())));
192 const Extension* extension = InstallExtensionFromWebstore(
193 test_data_dir_.AppendASCII("content_verifier/v1.crx"), 1);
194 ASSERT_TRUE(extension);
195 id_ = extension->id();
196 page_url_ = extension->GetResourceURL("page.html");
197 delegate_.set_id(id_);
198 ContentVerifyJob::SetDelegateForTests(&delegate_);
200 // This call passes false for |check_navigation_success|, because checking
201 // for navigation success needs the WebContents to still exist after the
202 // navigation, whereas this navigation triggers an unload which destroys
203 // the WebContents.
204 AddTabAtIndexToBrowser(browser(), 1, page_url_, ui::PAGE_TRANSITION_LINK,
205 false);
207 unload_observer_->WaitForUnload(id_);
208 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
209 int reasons = prefs->GetDisableReasons(id_);
210 EXPECT_TRUE(reasons & Extension::DISABLE_CORRUPTED);
212 // This needs to happen before the ExtensionRegistry gets deleted, which
213 // happens before TearDownOnMainThread is called.
214 unload_observer_.reset();
217 protected:
218 JobDelegate delegate_;
219 scoped_ptr<UnloadObserver> unload_observer_;
220 ExtensionId id_;
221 GURL page_url_;
224 IN_PROC_BROWSER_TEST_F(ContentVerifierTest, FailOnRead) {
225 delegate_.fail_next_read();
226 OpenPageAndWaitForUnload();
229 IN_PROC_BROWSER_TEST_F(ContentVerifierTest, FailOnDone) {
230 delegate_.fail_next_done();
231 OpenPageAndWaitForUnload();
234 IN_PROC_BROWSER_TEST_F(ContentVerifierTest, DotSlashPaths) {
235 JobObserver job_observer;
236 ContentVerifyJob::SetObserverForTests(&job_observer);
237 std::string id = "hoipipabpcoomfapcecilckodldhmpgl";
239 job_observer.ExpectJobResult(
240 id, base::FilePath(FILE_PATH_LITERAL("background.js")), false);
241 job_observer.ExpectJobResult(
242 id, base::FilePath(FILE_PATH_LITERAL("page.html")), false);
243 job_observer.ExpectJobResult(
244 id, base::FilePath(FILE_PATH_LITERAL("page.js")), false);
245 job_observer.ExpectJobResult(
246 id, base::FilePath(FILE_PATH_LITERAL("dir/page2.html")), false);
247 job_observer.ExpectJobResult(
248 id, base::FilePath(FILE_PATH_LITERAL("page2.js")), false);
250 // Install a test extension we copied from the webstore that has actual
251 // signatures, and contains image paths with leading "./".
252 const Extension* extension = InstallExtensionFromWebstore(
253 test_data_dir_.AppendASCII("content_verifier/dot_slash_paths.crx"), 1);
255 ASSERT_TRUE(extension);
256 ASSERT_EQ(extension->id(), id);
258 EXPECT_TRUE(job_observer.WaitForExpectedJobs());
260 ContentVerifyJob::SetObserverForTests(NULL);
263 } // namespace extensions