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