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.
4
5#include "base/bind.h"
6#include "base/message_loop/message_loop.h"
7#include "base/run_loop.h"
8#include "chrome/browser/extensions/extension_install_checker.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace extensions {
12
13namespace {
14
15const BlacklistState kBlacklistStateError = BLACKLISTED_MALWARE;
16const char kDummyRequirementsError[] = "Requirements error";
17const char kDummyPolicyError[] = "Cannot install extension";
18
19const char kDummyPolicyError2[] = "Another policy error";
20const char kDummyRequirementsError2[] = "Another requirements error";
21const BlacklistState kBlacklistState2 = BLACKLISTED_SECURITY_VULNERABILITY;
22
23}  // namespace
24
25// Stubs most of the checks since we are interested in validating the logic in
26// the install checker. This class implements a synchronous version of all
27// checks.
28class ExtensionInstallCheckerForTest : public ExtensionInstallChecker {
29 public:
30  ExtensionInstallCheckerForTest()
31      : ExtensionInstallChecker(NULL),
32        requirements_check_called_(false),
33        blacklist_check_called_(false),
34        policy_check_called_(false),
35        blacklist_state_(NOT_BLACKLISTED) {}
36
37  virtual ~ExtensionInstallCheckerForTest() {}
38
39  void set_requirements_error(const std::string& error) {
40    requirements_error_ = error;
41  }
42  void set_policy_check_error(const std::string& error) {
43    policy_check_error_ = error;
44  }
45  void set_blacklist_state(BlacklistState state) { blacklist_state_ = state; }
46
47  bool requirements_check_called() const { return requirements_check_called_; }
48  bool blacklist_check_called() const { return blacklist_check_called_; }
49  bool policy_check_called() const { return policy_check_called_; }
50
51  void MockCheckRequirements(int sequence_number) {
52    std::vector<std::string> errors;
53    if (!requirements_error_.empty())
54      errors.push_back(requirements_error_);
55    OnRequirementsCheckDone(sequence_number, errors);
56  }
57
58  void MockCheckBlacklistState(int sequence_number) {
59    OnBlacklistStateCheckDone(sequence_number, blacklist_state_);
60  }
61
62 protected:
63  virtual void CheckRequirements() OVERRIDE {
64    requirements_check_called_ = true;
65    MockCheckRequirements(current_sequence_number());
66  }
67
68  virtual void CheckManagementPolicy() OVERRIDE {
69    policy_check_called_ = true;
70    OnManagementPolicyCheckDone(policy_check_error_.empty(),
71                                policy_check_error_);
72  }
73
74  virtual void CheckBlacklistState() OVERRIDE {
75    blacklist_check_called_ = true;
76    MockCheckBlacklistState(current_sequence_number());
77  }
78
79  virtual void ResetResults() OVERRIDE {
80    ExtensionInstallChecker::ResetResults();
81
82    requirements_check_called_ = false;
83    blacklist_check_called_ = false;
84    policy_check_called_ = false;
85  }
86
87  bool requirements_check_called_;
88  bool blacklist_check_called_;
89  bool policy_check_called_;
90
91  // Dummy errors for testing.
92  std::string requirements_error_;
93  std::string policy_check_error_;
94  BlacklistState blacklist_state_;
95};
96
97// This class implements asynchronous mocks of the requirements and blacklist
98// checks.
99class ExtensionInstallCheckerAsync : public ExtensionInstallCheckerForTest {
100 protected:
101  virtual void CheckRequirements() OVERRIDE {
102    requirements_check_called_ = true;
103
104    base::MessageLoop::current()->PostTask(
105        FROM_HERE,
106        base::Bind(&ExtensionInstallCheckerForTest::MockCheckRequirements,
107                   base::Unretained(this),
108                   current_sequence_number()));
109  }
110
111  virtual void CheckBlacklistState() OVERRIDE {
112    blacklist_check_called_ = true;
113
114    base::MessageLoop::current()->PostTask(
115        FROM_HERE,
116        base::Bind(&ExtensionInstallCheckerForTest::MockCheckBlacklistState,
117                   base::Unretained(this),
118                   current_sequence_number()));
119  }
120};
121
122class CheckObserver {
123 public:
124  CheckObserver() : result_(0), call_count_(0) {}
125
126  int result() const { return result_; }
127  int call_count() const { return call_count_; }
128
129  void OnChecksComplete(int checks_failed) {
130    result_ = checks_failed;
131    ++call_count_;
132  }
133
134  void Wait() {
135    if (call_count_)
136      return;
137
138    base::RunLoop().RunUntilIdle();
139  }
140
141 private:
142  int result_;
143  int call_count_;
144};
145
146class ExtensionInstallCheckerTest : public testing::Test {
147 public:
148  ExtensionInstallCheckerTest() {}
149  virtual ~ExtensionInstallCheckerTest() {}
150
151  void RunSecondInvocation(ExtensionInstallCheckerForTest* checker,
152                           int checks_failed) {
153    EXPECT_GT(checks_failed, 0);
154    EXPECT_FALSE(checker->is_running());
155    ValidateExpectedCalls(ExtensionInstallChecker::CHECK_ALL, *checker);
156
157    // Set up different return values.
158    checker->set_blacklist_state(kBlacklistState2);
159    checker->set_policy_check_error(kDummyPolicyError2);
160    checker->set_requirements_error(kDummyRequirementsError2);
161
162    // Run the install checker again and ensure the second set of return values
163    // is received.
164    checker->Start(
165        ExtensionInstallChecker::CHECK_ALL,
166        false /* fail fast */,
167        base::Bind(&ExtensionInstallCheckerTest::ValidateSecondInvocation,
168                   base::Unretained(this),
169                   checker));
170  }
171
172  void ValidateSecondInvocation(ExtensionInstallCheckerForTest* checker,
173                                int checks_failed) {
174    EXPECT_FALSE(checker->is_running());
175    EXPECT_EQ(ExtensionInstallChecker::CHECK_REQUIREMENTS |
176                  ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY,
177              checks_failed);
178    ValidateExpectedCalls(ExtensionInstallChecker::CHECK_ALL, *checker);
179
180    EXPECT_EQ(kBlacklistState2, checker->blacklist_state());
181    ExpectPolicyError(kDummyPolicyError2, *checker);
182    ExpectRequirementsError(kDummyRequirementsError2, *checker);
183  }
184
185 protected:
186  void SetAllErrors(ExtensionInstallCheckerForTest* checker) {
187    checker->set_blacklist_state(kBlacklistStateError);
188    checker->set_policy_check_error(kDummyPolicyError);
189    checker->set_requirements_error(kDummyRequirementsError);
190  }
191
192  void ValidateExpectedCalls(int call_mask,
193                             const ExtensionInstallCheckerForTest& checker) {
194    bool expect_blacklist_checked =
195        (call_mask & ExtensionInstallChecker::CHECK_BLACKLIST) != 0;
196    bool expect_requirements_checked =
197        (call_mask & ExtensionInstallChecker::CHECK_REQUIREMENTS) != 0;
198    bool expect_policy_checked =
199        (call_mask & ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY) != 0;
200    EXPECT_EQ(expect_blacklist_checked, checker.blacklist_check_called());
201    EXPECT_EQ(expect_policy_checked, checker.policy_check_called());
202    EXPECT_EQ(expect_requirements_checked, checker.requirements_check_called());
203  }
204
205  void ExpectRequirementsPass(const ExtensionInstallCheckerForTest& checker) {
206    EXPECT_TRUE(checker.requirement_errors().empty());
207  }
208
209  void ExpectRequirementsError(const char* expected_error,
210                               const ExtensionInstallCheckerForTest& checker) {
211    EXPECT_FALSE(checker.requirement_errors().empty());
212    EXPECT_EQ(std::string(expected_error),
213              checker.requirement_errors().front());
214  }
215
216  void ExpectRequirementsError(const ExtensionInstallCheckerForTest& checker) {
217    ExpectRequirementsError(kDummyRequirementsError, checker);
218  }
219
220  void ExpectBlacklistPass(const ExtensionInstallCheckerForTest& checker) {
221    EXPECT_EQ(NOT_BLACKLISTED, checker.blacklist_state());
222  }
223
224  void ExpectBlacklistError(const ExtensionInstallCheckerForTest& checker) {
225    EXPECT_EQ(kBlacklistStateError, checker.blacklist_state());
226  }
227
228  void ExpectPolicyPass(const ExtensionInstallCheckerForTest& checker) {
229    EXPECT_TRUE(checker.policy_allows_load());
230    EXPECT_TRUE(checker.policy_error().empty());
231  }
232
233  void ExpectPolicyError(const char* expected_error,
234                         const ExtensionInstallCheckerForTest& checker) {
235    EXPECT_FALSE(checker.policy_allows_load());
236    EXPECT_FALSE(checker.policy_error().empty());
237    EXPECT_EQ(std::string(expected_error), checker.policy_error());
238  }
239
240  void ExpectPolicyError(const ExtensionInstallCheckerForTest& checker) {
241    ExpectPolicyError(kDummyPolicyError, checker);
242  }
243
244  void RunChecker(ExtensionInstallCheckerForTest* checker,
245                  bool fail_fast,
246                  int checks_to_run,
247                  int expected_checks_run,
248                  int expected_result) {
249    CheckObserver observer;
250    checker->Start(checks_to_run,
251                   fail_fast,
252                   base::Bind(&CheckObserver::OnChecksComplete,
253                              base::Unretained(&observer)));
254    observer.Wait();
255
256    EXPECT_FALSE(checker->is_running());
257    EXPECT_EQ(expected_result, observer.result());
258    EXPECT_EQ(1, observer.call_count());
259    ValidateExpectedCalls(expected_checks_run, *checker);
260  }
261
262  void DoRunAllChecksPass(ExtensionInstallCheckerForTest* checker) {
263    RunChecker(checker,
264               false /* fail fast */,
265               ExtensionInstallChecker::CHECK_ALL,
266               ExtensionInstallChecker::CHECK_ALL,
267               0);
268
269    ExpectRequirementsPass(*checker);
270    ExpectPolicyPass(*checker);
271    ExpectBlacklistPass(*checker);
272  }
273
274  void DoRunAllChecksFail(ExtensionInstallCheckerForTest* checker) {
275    SetAllErrors(checker);
276    RunChecker(checker,
277               false /* fail fast */,
278               ExtensionInstallChecker::CHECK_ALL,
279               ExtensionInstallChecker::CHECK_ALL,
280               ExtensionInstallChecker::CHECK_ALL);
281
282    ExpectRequirementsError(*checker);
283    ExpectPolicyError(*checker);
284    ExpectBlacklistError(*checker);
285  }
286
287  void DoRunSubsetOfChecks(ExtensionInstallCheckerForTest* checker) {
288    // Test check set 1.
289    int tests_to_run = ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY |
290                       ExtensionInstallChecker::CHECK_REQUIREMENTS;
291    SetAllErrors(checker);
292    RunChecker(checker, false, tests_to_run, tests_to_run, tests_to_run);
293
294    ExpectRequirementsError(*checker);
295    ExpectPolicyError(*checker);
296    ExpectBlacklistPass(*checker);
297
298    // Test check set 2.
299    tests_to_run = ExtensionInstallChecker::CHECK_BLACKLIST |
300                   ExtensionInstallChecker::CHECK_REQUIREMENTS;
301    SetAllErrors(checker);
302    RunChecker(checker, false, tests_to_run, tests_to_run, tests_to_run);
303
304    ExpectRequirementsError(*checker);
305    ExpectPolicyPass(*checker);
306    ExpectBlacklistError(*checker);
307
308    // Test a single check.
309    tests_to_run = ExtensionInstallChecker::CHECK_BLACKLIST;
310    SetAllErrors(checker);
311    RunChecker(checker, false, tests_to_run, tests_to_run, tests_to_run);
312
313    ExpectRequirementsPass(*checker);
314    ExpectPolicyPass(*checker);
315    ExpectBlacklistError(*checker);
316  }
317
318 private:
319  // A message loop is required for the asynchronous tests.
320  base::MessageLoop message_loop;
321};
322
323class ExtensionInstallCheckerMultipleInvocationTest
324    : public ExtensionInstallCheckerTest {
325 public:
326  ExtensionInstallCheckerMultipleInvocationTest() : callback_count_(0) {}
327  virtual ~ExtensionInstallCheckerMultipleInvocationTest() {}
328
329  void RunSecondInvocation(ExtensionInstallCheckerForTest* checker,
330                           int checks_failed) {
331    ASSERT_EQ(0, callback_count_);
332    ++callback_count_;
333    EXPECT_FALSE(checker->is_running());
334    EXPECT_GT(checks_failed, 0);
335    ValidateExpectedCalls(ExtensionInstallChecker::CHECK_ALL, *checker);
336
337    // Set up different return values.
338    checker->set_blacklist_state(kBlacklistState2);
339    checker->set_policy_check_error(kDummyPolicyError2);
340    checker->set_requirements_error(kDummyRequirementsError2);
341
342    // Run the install checker again and ensure the second set of return values
343    // is received.
344    checker->Start(ExtensionInstallChecker::CHECK_ALL,
345                   false /* fail fast */,
346                   base::Bind(&ExtensionInstallCheckerMultipleInvocationTest::
347                                  ValidateSecondInvocation,
348                              base::Unretained(this),
349                              checker));
350  }
351
352  void ValidateSecondInvocation(ExtensionInstallCheckerForTest* checker,
353                                int checks_failed) {
354    ASSERT_EQ(1, callback_count_);
355    EXPECT_FALSE(checker->is_running());
356    EXPECT_EQ(ExtensionInstallChecker::CHECK_REQUIREMENTS |
357                  ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY,
358              checks_failed);
359    ValidateExpectedCalls(ExtensionInstallChecker::CHECK_ALL, *checker);
360
361    EXPECT_EQ(kBlacklistState2, checker->blacklist_state());
362    ExpectPolicyError(kDummyPolicyError2, *checker);
363    ExpectRequirementsError(kDummyRequirementsError2, *checker);
364  }
365
366 private:
367  int callback_count_;
368};
369
370// Test the case where all tests pass.
371TEST_F(ExtensionInstallCheckerTest, AllSucceeded) {
372  ExtensionInstallCheckerForTest sync_checker;
373  DoRunAllChecksPass(&sync_checker);
374
375  ExtensionInstallCheckerAsync async_checker;
376  DoRunAllChecksPass(&async_checker);
377}
378
379// Test the case where all tests fail.
380TEST_F(ExtensionInstallCheckerTest, AllFailed) {
381  ExtensionInstallCheckerForTest sync_checker;
382  DoRunAllChecksFail(&sync_checker);
383
384  ExtensionInstallCheckerAsync async_checker;
385  DoRunAllChecksFail(&async_checker);
386}
387
388// Test running only a subset of tests.
389TEST_F(ExtensionInstallCheckerTest, RunSubsetOfChecks) {
390  ExtensionInstallCheckerForTest sync_checker;
391  ExtensionInstallCheckerAsync async_checker;
392  DoRunSubsetOfChecks(&sync_checker);
393  DoRunSubsetOfChecks(&async_checker);
394}
395
396// Test fail fast with synchronous callbacks.
397TEST_F(ExtensionInstallCheckerTest, FailFastSync) {
398  // This test assumes some internal knowledge of the implementation - that
399  // the policy check runs first.
400  ExtensionInstallCheckerForTest checker;
401  SetAllErrors(&checker);
402  RunChecker(&checker,
403             true /* fail fast */,
404             ExtensionInstallChecker::CHECK_ALL,
405             ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY,
406             ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY);
407
408  ExpectRequirementsPass(checker);
409  ExpectPolicyError(checker);
410  ExpectBlacklistPass(checker);
411
412  // This test assumes some internal knowledge of the implementation - that
413  // the requirements check runs before the blacklist check.
414  SetAllErrors(&checker);
415  RunChecker(&checker,
416             true /* fail fast */,
417             ExtensionInstallChecker::CHECK_REQUIREMENTS |
418                 ExtensionInstallChecker::CHECK_BLACKLIST,
419             ExtensionInstallChecker::CHECK_REQUIREMENTS,
420             ExtensionInstallChecker::CHECK_REQUIREMENTS);
421
422  ExpectRequirementsError(checker);
423  ExpectPolicyPass(checker);
424  ExpectBlacklistPass(checker);
425}
426
427// Test fail fast with asynchronous callbacks.
428TEST_F(ExtensionInstallCheckerTest, FailFastAsync) {
429  // This test assumes some internal knowledge of the implementation - that
430  // the requirements check runs before the blacklist check. Both checks should
431  // be called, but the requirements check callback arrives first and the
432  // blacklist result will be discarded.
433  ExtensionInstallCheckerAsync checker;
434  SetAllErrors(&checker);
435
436  // The policy check is synchronous and needs to pass for the other tests to
437  // run.
438  checker.set_policy_check_error(std::string());
439
440  RunChecker(&checker,
441             true /* fail fast */,
442             ExtensionInstallChecker::CHECK_ALL,
443             ExtensionInstallChecker::CHECK_ALL,
444             ExtensionInstallChecker::CHECK_REQUIREMENTS);
445
446  ExpectRequirementsError(checker);
447  ExpectPolicyPass(checker);
448  ExpectBlacklistPass(checker);
449}
450
451// Test multiple invocations of the install checker. Wait for all checks to
452// complete.
453TEST_F(ExtensionInstallCheckerMultipleInvocationTest, CompleteAll) {
454  ExtensionInstallCheckerAsync checker;
455  SetAllErrors(&checker);
456
457  // Start the second check as soon as the callback of the first run is invoked.
458  checker.Start(
459      ExtensionInstallChecker::CHECK_ALL,
460      false /* fail fast */,
461      base::Bind(
462          &ExtensionInstallCheckerMultipleInvocationTest::RunSecondInvocation,
463          base::Unretained(this),
464          &checker));
465  base::RunLoop().RunUntilIdle();
466}
467
468// Test multiple invocations of the install checker and fail fast.
469TEST_F(ExtensionInstallCheckerMultipleInvocationTest, FailFast) {
470  ExtensionInstallCheckerAsync checker;
471  SetAllErrors(&checker);
472
473  // The policy check is synchronous and needs to pass for the other tests to
474  // run.
475  checker.set_policy_check_error(std::string());
476
477  // Start the second check as soon as the callback of the first run is invoked.
478  checker.Start(
479      ExtensionInstallChecker::CHECK_ALL,
480      true /* fail fast */,
481      base::Bind(
482          &ExtensionInstallCheckerMultipleInvocationTest::RunSecondInvocation,
483          base::Unretained(this),
484          &checker));
485  base::RunLoop().RunUntilIdle();
486}
487
488}  // namespace extensions
489