Home | History | Annotate | Download | only in extensions
      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 
     11 namespace extensions {
     12 
     13 namespace {
     14 
     15 const BlacklistState kBlacklistStateError = BLACKLISTED_MALWARE;
     16 const char kDummyRequirementsError[] = "Requirements error";
     17 const char kDummyPolicyError[] = "Cannot install extension";
     18 
     19 const char kDummyPolicyError2[] = "Another policy error";
     20 const char kDummyRequirementsError2[] = "Another requirements error";
     21 const 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.
     28 class 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.
     99 class 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 
    122 class 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 
    146 class 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 
    323 class 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.
    371 TEST_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.
    380 TEST_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.
    389 TEST_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.
    397 TEST_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.
    428 TEST_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.
    453 TEST_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.
    469 TEST_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