component_updater_service_unittest.cc revision ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16
1// Copyright (c) 2012 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 "chrome/browser/component_updater/test/component_updater_service_unittest.h" 6#include "base/file_util.h" 7#include "base/files/file_path.h" 8#include "base/memory/scoped_vector.h" 9#include "base/path_service.h" 10#include "base/strings/string_number_conversions.h" 11#include "base/strings/stringprintf.h" 12#include "base/values.h" 13#include "chrome/browser/component_updater/component_updater_service.h" 14#include "chrome/browser/component_updater/test/test_installer.h" 15#include "chrome/common/chrome_paths.h" 16#include "content/test/net/url_request_prepackaged_interceptor.h" 17#include "libxml/globals.h" 18#include "net/base/upload_bytes_element_reader.h" 19#include "net/url_request/url_fetcher.h" 20#include "url/gurl.h" 21 22using content::BrowserThread; 23 24using ::testing::_; 25using ::testing::InSequence; 26using ::testing::Mock; 27 28MockComponentObserver::MockComponentObserver() { 29} 30 31MockComponentObserver::~MockComponentObserver() { 32} 33 34TestConfigurator::TestConfigurator() 35 : times_(1), 36 recheck_time_(0), 37 ondemand_time_(0), 38 cus_(NULL), 39 context_(new net::TestURLRequestContextGetter( 40 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) { 41} 42 43TestConfigurator::~TestConfigurator() { 44} 45 46int TestConfigurator::InitialDelay() { return 0; } 47 48int TestConfigurator::NextCheckDelay() { 49 // This is called when a new full cycle of checking for updates is going 50 // to happen. In test we normally only test one cycle so it is a good 51 // time to break from the test messageloop Run() method so the test can 52 // finish. 53 if (--times_ <= 0) { 54 base::MessageLoop::current()->Quit(); 55 return 0; 56 } 57 58 // Look for checks to issue in the middle of the loop. 59 for (std::list<CheckAtLoopCount>::iterator 60 i = components_to_check_.begin(); 61 i != components_to_check_.end(); ) { 62 if (i->second == times_) { 63 cus_->CheckForUpdateSoon(*i->first); 64 i = components_to_check_.erase(i); 65 } else { 66 ++i; 67 } 68 } 69 return 1; 70} 71 72int TestConfigurator::StepDelay() { 73 return 0; 74} 75 76int TestConfigurator::MinimumReCheckWait() { 77 return recheck_time_; 78} 79 80int TestConfigurator::OnDemandDelay() { 81 return ondemand_time_; 82} 83 84GURL TestConfigurator::UpdateUrl() { 85 return GURL("http://localhost/upd"); 86} 87 88GURL TestConfigurator::PingUrl() { 89 return GURL("http://localhost2/ping"); 90} 91 92const char* TestConfigurator::ExtraRequestParams() { return "extra=foo"; } 93 94size_t TestConfigurator::UrlSizeLimit() { return 256; } 95 96net::URLRequestContextGetter* TestConfigurator::RequestContext() { 97 return context_.get(); 98} 99 100// Don't use the utility process to decode files. 101bool TestConfigurator::InProcess() { return true; } 102 103ComponentPatcher* TestConfigurator::CreateComponentPatcher() { 104 return new MockComponentPatcher(); 105} 106 107bool TestConfigurator::DeltasEnabled() const { 108 return true; 109} 110 111// Set how many update checks are called, the default value is just once. 112void TestConfigurator::SetLoopCount(int times) { times_ = times; } 113 114void TestConfigurator::SetRecheckTime(int seconds) { 115 recheck_time_ = seconds; 116} 117 118void TestConfigurator::SetOnDemandTime(int seconds) { 119 ondemand_time_ = seconds; 120} 121 122void TestConfigurator::AddComponentToCheck(CrxComponent* com, 123 int at_loop_iter) { 124 components_to_check_.push_back(std::make_pair(com, at_loop_iter)); 125} 126 127void TestConfigurator::SetComponentUpdateService(ComponentUpdateService* cus) { 128 cus_ = cus; 129} 130 131ComponentUpdaterTest::ComponentUpdaterTest() 132 : test_config_(NULL), 133 ui_thread_(BrowserThread::UI, &message_loop_), 134 file_thread_(BrowserThread::FILE), 135 io_thread_(BrowserThread::IO) { 136 // The component updater instance under test. 137 test_config_ = new TestConfigurator; 138 component_updater_.reset(ComponentUpdateServiceFactory(test_config_)); 139 test_config_->SetComponentUpdateService(component_updater_.get()); 140 141 // The test directory is chrome/test/data/components. 142 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); 143 test_data_dir_ = test_data_dir_.AppendASCII("components"); 144 145 net::URLFetcher::SetEnableInterceptionForTests(true); 146 147 io_thread_.StartIOThread(); 148 file_thread_.Start(); 149} 150 151ComponentUpdaterTest::~ComponentUpdaterTest() { 152 net::URLFetcher::SetEnableInterceptionForTests(false); 153} 154 155void ComponentUpdaterTest::TearDown() { 156 xmlCleanupGlobals(); 157} 158 159ComponentUpdateService* ComponentUpdaterTest::component_updater() { 160 return component_updater_.get(); 161} 162 163 // Makes the full path to a component updater test file. 164const base::FilePath ComponentUpdaterTest::test_file(const char* file) { 165 return test_data_dir_.AppendASCII(file); 166} 167 168TestConfigurator* ComponentUpdaterTest::test_configurator() { 169 return test_config_; 170} 171 172ComponentUpdateService::Status ComponentUpdaterTest::RegisterComponent( 173 CrxComponent* com, 174 TestComponents component, 175 const Version& version, 176 TestInstaller* installer) { 177 if (component == kTestComponent_abag) { 178 com->name = "test_abag"; 179 com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash)); 180 } else if (component == kTestComponent_jebg) { 181 com->name = "test_jebg"; 182 com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); 183 } else { 184 com->name = "test_ihfo"; 185 com->pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); 186 } 187 com->version = version; 188 com->installer = installer; 189 return component_updater_->RegisterComponent(*com); 190} 191 192PingChecker::PingChecker(const std::map<std::string, std::string>& attributes) 193 : num_hits_(0), num_misses_(0), attributes_(attributes) { 194} 195 196PingChecker::~PingChecker() {} 197 198void PingChecker::Trial(net::URLRequest* request) { 199 if (Test(request)) 200 ++num_hits_; 201 else 202 ++num_misses_; 203} 204 205bool PingChecker::Test(net::URLRequest* request) { 206 if (request->has_upload()) { 207 const net::UploadDataStream* stream = request->get_upload(); 208 const net::UploadBytesElementReader* reader = 209 stream->element_readers()[0]->AsBytesReader(); 210 int size = reader->length(); 211 scoped_refptr <net::IOBuffer> buffer = new net::IOBuffer(size); 212 std::string data(reader->bytes()); 213 // For now, we assume that there is only one ping per POST. 214 std::string::size_type start = data.find("<o:event"); 215 if (start != std::string::npos) { 216 std::string::size_type end = data.find(">", start); 217 if (end != std::string::npos) { 218 std::string ping = data.substr(start, end - start); 219 std::map<std::string, std::string>::const_iterator iter; 220 for (iter = attributes_.begin(); iter != attributes_.end(); ++iter) { 221 // does the ping contain the specified attribute/value? 222 if (ping.find(std::string(" ") + (iter->first) + 223 std::string("=") + (iter->second)) == string::npos) { 224 return false; 225 } 226 } 227 return true; 228 } 229 } 230 } 231 return false; 232} 233 234// Verify that our test fixture work and the component updater can 235// be created and destroyed with no side effects. 236TEST_F(ComponentUpdaterTest, VerifyFixture) { 237 EXPECT_TRUE(component_updater() != NULL); 238} 239 240// Verify that the component updater can be caught in a quick 241// start-shutdown situation. Failure of this test will be a crash. 242TEST_F(ComponentUpdaterTest, StartStop) { 243 component_updater()->Start(); 244 message_loop_.RunUntilIdle(); 245 component_updater()->Stop(); 246} 247 248// Verify that when the server has no updates, we go back to sleep and 249// the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications 250// are generated. 251TEST_F(ComponentUpdaterTest, CheckCrxSleep) { 252 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 253 254 MockComponentObserver observer; 255 256 TestInstaller installer; 257 CrxComponent com; 258 com.observer = &observer; 259 EXPECT_EQ(ComponentUpdateService::kOk, 260 RegisterComponent(&com, 261 kTestComponent_abag, 262 Version("1.1"), 263 &installer)); 264 265 const GURL expected_update_url( 266 "http://localhost/upd?extra=foo" 267 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D1.1%26fp%3D%26uc"); 268 269 interceptor.SetResponse(expected_update_url, 270 test_file("updatecheck_reply_1.xml")); 271 272 // We loop twice, but there are no updates so we expect two sleep messages. 273 test_configurator()->SetLoopCount(2); 274 275 EXPECT_CALL(observer, 276 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 277 .Times(1); 278 component_updater()->Start(); 279 280 EXPECT_CALL(observer, 281 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 282 .Times(2); 283 message_loop_.Run(); 284 285 EXPECT_EQ(2, interceptor.GetHitCount()); 286 287 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 288 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count()); 289 290 component_updater()->Stop(); 291 292 // Loop twice again but this case we simulate a server error by returning 293 // an empty file. 294 295 interceptor.SetResponse(expected_update_url, 296 test_file("updatecheck_reply_empty")); 297 298 test_configurator()->SetLoopCount(2); 299 300 EXPECT_CALL(observer, 301 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 302 .Times(1); 303 component_updater()->Start(); 304 305 EXPECT_CALL(observer, 306 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 307 .Times(2); 308 message_loop_.Run(); 309 310 EXPECT_EQ(4, interceptor.GetHitCount()); 311 312 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 313 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count()); 314 315 component_updater()->Stop(); 316} 317 318// Verify that we can check for updates and install one component. Besides 319// the notifications above COMPONENT_UPDATE_FOUND and COMPONENT_UPDATE_READY 320// should have been fired. We do two loops so the second time around there 321// should be nothing left to do. 322// We also check that only 3 non-ping network requests are issued: 323// 1- manifest check 324// 2- download crx 325// 3- second manifest check. 326TEST_F(ComponentUpdaterTest, InstallCrx) { 327 std::map<std::string, std::string> map; 328 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 329 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 330 map.insert(std::pair<std::string, std::string>("previousversion", 331 "\"0.9\"")); 332 map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\"")); 333 PingChecker ping_checker(map); 334 URLRequestPostInterceptor post_interceptor(&ping_checker); 335 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 336 337 MockComponentObserver observer1; 338 { 339 InSequence seq; 340 EXPECT_CALL(observer1, 341 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 342 .Times(1); 343 EXPECT_CALL(observer1, 344 OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0)) 345 .Times(1); 346 EXPECT_CALL(observer1, 347 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0)) 348 .Times(1); 349 EXPECT_CALL(observer1, 350 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 351 .Times(2); 352 } 353 354 MockComponentObserver observer2; 355 { 356 InSequence seq; 357 EXPECT_CALL(observer2, 358 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 359 .Times(1); 360 EXPECT_CALL(observer2, 361 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 362 .Times(2); 363 } 364 365 TestInstaller installer1; 366 CrxComponent com1; 367 com1.observer = &observer1; 368 RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1); 369 TestInstaller installer2; 370 CrxComponent com2; 371 com2.observer = &observer2; 372 RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2); 373 374 const GURL expected_update_url_1( 375 "http://localhost/upd?extra=foo" 376 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc" 377 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"); 378 379 const GURL expected_update_url_2( 380 "http://localhost/upd?extra=foo" 381 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc" 382 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc"); 383 384 interceptor.SetResponse(expected_update_url_1, 385 test_file("updatecheck_reply_1.xml")); 386 interceptor.SetResponse(expected_update_url_2, 387 test_file("updatecheck_reply_1.xml")); 388 interceptor.SetResponse(GURL(expected_crx_url), 389 test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); 390 391 test_configurator()->SetLoopCount(2); 392 393 component_updater()->Start(); 394 message_loop_.Run(); 395 396 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error()); 397 EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count()); 398 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error()); 399 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count()); 400 401 EXPECT_EQ(3, interceptor.GetHitCount()); 402 EXPECT_EQ(1, ping_checker.NumHits()); 403 EXPECT_EQ(0, ping_checker.NumMisses()); 404 405 component_updater()->Stop(); 406} 407 408// This test checks that the "prodversionmin" value is handled correctly. In 409// particular there should not be an install because the minimum product 410// version is much higher than of chrome. 411TEST_F(ComponentUpdaterTest, ProdVersionCheck) { 412 std::map<std::string, std::string> map; 413 PingChecker ping_checker(map); 414 URLRequestPostInterceptor post_interceptor(&ping_checker); 415 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 416 417 TestInstaller installer; 418 CrxComponent com; 419 RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), &installer); 420 421 const GURL expected_update_url( 422 "http://localhost/upd?extra=foo&x=id%3D" 423 "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"); 424 425 interceptor.SetResponse(expected_update_url, 426 test_file("updatecheck_reply_2.xml")); 427 interceptor.SetResponse(GURL(expected_crx_url), 428 test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); 429 430 test_configurator()->SetLoopCount(1); 431 component_updater()->Start(); 432 message_loop_.Run(); 433 434 EXPECT_EQ(0, ping_checker.NumHits()); 435 EXPECT_EQ(0, ping_checker.NumMisses()); 436 EXPECT_EQ(1, interceptor.GetHitCount()); 437 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 438 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count()); 439 440 component_updater()->Stop(); 441} 442 443// Test that a ping for an update check can cause installs. 444// Here is the timeline: 445// - First loop: we return a reply that indicates no update, so 446// nothing happens. 447// - We ping. 448// - This triggers a second loop, which has a reply that triggers an install. 449TEST_F(ComponentUpdaterTest, CheckForUpdateSoon) { 450 std::map<std::string, std::string> map; 451 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 452 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 453 map.insert(std::pair<std::string, std::string>("previousversion", 454 "\"0.9\"")); 455 map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\"")); 456 PingChecker ping_checker(map); 457 URLRequestPostInterceptor post_interceptor(&ping_checker); 458 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 459 460 MockComponentObserver observer1; 461 { 462 InSequence seq; 463 EXPECT_CALL(observer1, 464 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 465 .Times(1); 466 EXPECT_CALL(observer1, 467 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 468 .Times(1); 469 EXPECT_CALL(observer1, 470 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 471 .Times(1); 472 } 473 474 MockComponentObserver observer2; 475 { 476 InSequence seq; 477 EXPECT_CALL(observer2, 478 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 479 .Times(1); 480 EXPECT_CALL(observer2, 481 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 482 .Times(1); 483 EXPECT_CALL(observer2, 484 OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0)) 485 .Times(1); 486 EXPECT_CALL(observer2, 487 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0)) 488 .Times(1); 489 EXPECT_CALL(observer2, 490 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 491 .Times(1); 492 } 493 494 TestInstaller installer1; 495 CrxComponent com1; 496 com1.observer = &observer1; 497 RegisterComponent(&com1, kTestComponent_abag, Version("2.2"), &installer1); 498 TestInstaller installer2; 499 CrxComponent com2; 500 com2.observer = &observer2; 501 RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"), &installer2); 502 503 const GURL expected_update_url_1( 504 "http://localhost/upd?extra=foo" 505 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc" 506 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"); 507 508 const GURL expected_update_url_2( 509 "http://localhost/upd?extra=foo" 510 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc" 511 "%26installsource%3Dondemand" 512 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"); 513 514 interceptor.SetResponse(expected_update_url_1, 515 test_file("updatecheck_reply_empty")); 516 interceptor.SetResponse(expected_update_url_2, 517 test_file("updatecheck_reply_1.xml")); 518 interceptor.SetResponse(GURL(expected_crx_url), 519 test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); 520 // Test success. 521 test_configurator()->SetLoopCount(2); 522 test_configurator()->AddComponentToCheck(&com2, 1); 523 component_updater()->Start(); 524 message_loop_.Run(); 525 526 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error()); 527 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count()); 528 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error()); 529 EXPECT_EQ(1, static_cast<TestInstaller*>(com2.installer)->install_count()); 530 531 EXPECT_EQ(3, interceptor.GetHitCount()); 532 533 // Also check what happens if previous check too soon. 534 test_configurator()->SetOnDemandTime(60 * 60); 535 EXPECT_EQ(ComponentUpdateService::kError, 536 component_updater()->CheckForUpdateSoon(com2)); 537 // Okay, now reset to 0 for the other tests. 538 test_configurator()->SetOnDemandTime(0); 539 component_updater()->Stop(); 540 541 // Test a few error cases. NOTE: We don't have callbacks for 542 // when the updates failed yet. 543 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1)); 544 { 545 InSequence seq; 546 EXPECT_CALL(observer1, 547 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 548 .Times(1); 549 EXPECT_CALL(observer1, 550 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 551 .Times(1); 552 } 553 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2)); 554 { 555 InSequence seq; 556 EXPECT_CALL(observer2, 557 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 558 .Times(1); 559 EXPECT_CALL(observer2, 560 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 561 .Times(1); 562 } 563 564 const GURL expected_update_url_3( 565 "http://localhost/upd?extra=foo" 566 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc" 567 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"); 568 569 // No update: error from no server response 570 interceptor.SetResponse(expected_update_url_3, 571 test_file("updatecheck_reply_empty")); 572 test_configurator()->SetLoopCount(1); 573 component_updater()->Start(); 574 EXPECT_EQ(ComponentUpdateService::kOk, 575 component_updater()->CheckForUpdateSoon(com2)); 576 577 message_loop_.Run(); 578 579 component_updater()->Stop(); 580 581 // No update: already updated to 1.0 so nothing new 582 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1)); 583 { 584 InSequence seq; 585 EXPECT_CALL(observer1, 586 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 587 .Times(1); 588 EXPECT_CALL(observer1, 589 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 590 .Times(1); 591 } 592 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2)); 593 { 594 InSequence seq; 595 EXPECT_CALL(observer2, 596 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 597 .Times(1); 598 EXPECT_CALL(observer2, 599 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 600 .Times(1); 601 } 602 603 interceptor.SetResponse(expected_update_url_3, 604 test_file("updatecheck_reply_1.xml")); 605 test_configurator()->SetLoopCount(1); 606 component_updater()->Start(); 607 EXPECT_EQ(ComponentUpdateService::kOk, 608 component_updater()->CheckForUpdateSoon(com2)); 609 610 message_loop_.Run(); 611 612 EXPECT_EQ(1, ping_checker.NumHits()); 613 EXPECT_EQ(0, ping_checker.NumMisses()); 614 615 component_updater()->Stop(); 616} 617 618// Verify that a previously registered component can get re-registered 619// with a different version. 620TEST_F(ComponentUpdaterTest, CheckReRegistration) { 621 std::map<std::string, std::string> map; 622 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 623 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 624 map.insert(std::pair<std::string, std::string>("previousversion", 625 "\"0.9\"")); 626 map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\"")); 627 PingChecker ping_checker(map); 628 URLRequestPostInterceptor post_interceptor(&ping_checker); 629 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 630 631 MockComponentObserver observer1; 632 { 633 InSequence seq; 634 EXPECT_CALL(observer1, 635 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 636 .Times(1); 637 EXPECT_CALL(observer1, 638 OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0)) 639 .Times(1); 640 EXPECT_CALL(observer1, 641 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0)) 642 .Times(1); 643 EXPECT_CALL(observer1, 644 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 645 .Times(1); 646 EXPECT_CALL(observer1, 647 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 648 .Times(1); 649 } 650 651 MockComponentObserver observer2; 652 { 653 InSequence seq; 654 EXPECT_CALL(observer2, 655 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 656 .Times(1); 657 EXPECT_CALL(observer2, 658 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 659 .Times(1); 660 EXPECT_CALL(observer2, 661 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 662 .Times(1); 663 } 664 665 TestInstaller installer1; 666 CrxComponent com1; 667 com1.observer = &observer1; 668 RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1); 669 TestInstaller installer2; 670 CrxComponent com2; 671 com2.observer = &observer2; 672 RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2); 673 674 // Start with 0.9, and update to 1.0 675 const GURL expected_update_url_1( 676 "http://localhost/upd?extra=foo" 677 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc" 678 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"); 679 680 const GURL expected_update_url_2( 681 "http://localhost/upd?extra=foo" 682 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc" 683 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc"); 684 685 interceptor.SetResponse(expected_update_url_1, 686 test_file("updatecheck_reply_1.xml")); 687 interceptor.SetResponse(expected_update_url_2, 688 test_file("updatecheck_reply_1.xml")); 689 interceptor.SetResponse(GURL(expected_crx_url), 690 test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); 691 692 // Loop twice to issue two checks: (1) with original 0.9 version 693 // and (2) with the updated 1.0 version. 694 test_configurator()->SetLoopCount(2); 695 696 component_updater()->Start(); 697 message_loop_.Run(); 698 699 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error()); 700 EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count()); 701 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error()); 702 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count()); 703 704 EXPECT_EQ(1, ping_checker.NumHits()); 705 EXPECT_EQ(0, ping_checker.NumMisses()); 706 EXPECT_EQ(3, interceptor.GetHitCount()); 707 708 component_updater()->Stop(); 709 710 // Now re-register, pretending to be an even newer version (2.2) 711 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1)); 712 { 713 InSequence seq; 714 EXPECT_CALL(observer1, 715 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 716 .Times(1); 717 EXPECT_CALL(observer1, 718 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 719 .Times(1); 720 } 721 722 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2)); 723 { 724 InSequence seq; 725 EXPECT_CALL(observer2, 726 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0)) 727 .Times(1); 728 EXPECT_CALL(observer2, 729 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0)) 730 .Times(1); 731 } 732 733 TestInstaller installer3; 734 EXPECT_EQ(ComponentUpdateService::kReplaced, 735 RegisterComponent(&com1, 736 kTestComponent_jebg, 737 Version("2.2"), 738 &installer3)); 739 740 // Check that we send out 2.2 as our version. 741 // Interceptor's hit count should go up by 1. 742 const GURL expected_update_url_3( 743 "http://localhost/upd?extra=foo" 744 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D2.2%26fp%3D%26uc" 745 "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"); 746 747 interceptor.SetResponse(expected_update_url_3, 748 test_file("updatecheck_reply_1.xml")); 749 750 // Loop once just to notice the check happening with the re-register version. 751 test_configurator()->SetLoopCount(1); 752 component_updater()->Start(); 753 message_loop_.Run(); 754 755 EXPECT_EQ(4, interceptor.GetHitCount()); 756 757 // We created a new installer, so the counts go back to 0. 758 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error()); 759 EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count()); 760 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error()); 761 EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count()); 762 763 component_updater()->Stop(); 764} 765 766// Verify that we can download and install a component and a differential 767// update to that component. We do three loops; the final loop should do 768// nothing. 769// We also check that exactly 5 non-ping network requests are issued: 770// 1- update check (response: v1 available) 771// 2- download crx (v1) 772// 3- update check (response: v2 available) 773// 4- download differential crx (v1 to v2) 774// 5- update check (response: no further update available) 775// There should be two pings, one for each update. The second will bear a 776// diffresult=1, while the first will not. 777TEST_F(ComponentUpdaterTest, DifferentialUpdate) { 778 std::map<std::string, std::string> map; 779 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 780 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 781 map.insert(std::pair<std::string, std::string>("diffresult", "\"1\"")); 782 PingChecker ping_checker(map); 783 URLRequestPostInterceptor post_interceptor(&ping_checker); 784 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 785 786 VersionedTestInstaller installer; 787 CrxComponent com; 788 RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), &installer); 789 790 const GURL expected_update_url_0( 791 "http://localhost/upd?extra=foo" 792 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D0.0%26fp%3D%26uc"); 793 const GURL expected_update_url_1( 794 "http://localhost/upd?extra=foo" 795 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D1%26uc"); 796 const GURL expected_update_url_2( 797 "http://localhost/upd?extra=foo" 798 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc"); 799 const GURL expected_crx_url_1( 800 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"); 801 const GURL expected_crx_url_1_diff_2( 802 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"); 803 804 interceptor.SetResponse(expected_update_url_0, 805 test_file("updatecheck_diff_reply_1.xml")); 806 interceptor.SetResponse(expected_update_url_1, 807 test_file("updatecheck_diff_reply_2.xml")); 808 interceptor.SetResponse(expected_update_url_2, 809 test_file("updatecheck_diff_reply_3.xml")); 810 interceptor.SetResponse(expected_crx_url_1, 811 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx")); 812 interceptor.SetResponse( 813 expected_crx_url_1_diff_2, 814 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx")); 815 816 test_configurator()->SetLoopCount(3); 817 818 component_updater()->Start(); 819 message_loop_.Run(); 820 821 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 822 EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count()); 823 824 // One ping has the diffresult=1, the other does not. 825 EXPECT_EQ(1, ping_checker.NumHits()); 826 EXPECT_EQ(1, ping_checker.NumMisses()); 827 828 EXPECT_EQ(5, interceptor.GetHitCount()); 829 830 component_updater()->Stop(); 831} 832 833// Verify that component installation falls back to downloading and installing 834// a full update if the differential update fails (in this case, because the 835// installer does not know about the existing files). We do two loops; the final 836// loop should do nothing. 837// We also check that exactly 4 non-ping network requests are issued: 838// 1- update check (loop 1) 839// 2- download differential crx 840// 3- download full crx 841// 4- update check (loop 2 - no update available) 842// There should be one ping for the first attempted update. 843 844TEST_F(ComponentUpdaterTest, DifferentialUpdateFails) { 845 std::map<std::string, std::string> map; 846 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 847 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 848 map.insert(std::pair<std::string, std::string>("diffresult", "\"0\"")); 849 map.insert(std::pair<std::string, std::string>("differrorcode", "\"16\"")); 850 PingChecker ping_checker(map); 851 URLRequestPostInterceptor post_interceptor(&ping_checker); 852 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 853 854 TestInstaller installer; 855 CrxComponent com; 856 RegisterComponent(&com, kTestComponent_ihfo, Version("1.0"), &installer); 857 858 const GURL expected_update_url_1( 859 "http://localhost/upd?extra=foo" 860 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D%26uc"); 861 const GURL expected_update_url_2( 862 "http://localhost/upd?extra=foo" 863 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc"); 864 const GURL expected_crx_url_1( 865 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"); 866 const GURL expected_crx_url_1_diff_2( 867 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"); 868 const GURL expected_crx_url_2( 869 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"); 870 871 interceptor.SetResponse(expected_update_url_1, 872 test_file("updatecheck_diff_reply_2.xml")); 873 interceptor.SetResponse(expected_update_url_2, 874 test_file("updatecheck_diff_reply_3.xml")); 875 interceptor.SetResponse(expected_crx_url_1, 876 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx")); 877 interceptor.SetResponse( 878 expected_crx_url_1_diff_2, 879 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx")); 880 interceptor.SetResponse(expected_crx_url_2, 881 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx")); 882 883 test_configurator()->SetLoopCount(2); 884 885 component_updater()->Start(); 886 message_loop_.Run(); 887 888 // A failed differential update does not count as a failed install. 889 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 890 EXPECT_EQ(1, static_cast<TestInstaller*>(com.installer)->install_count()); 891 892 EXPECT_EQ(1, ping_checker.NumHits()); 893 EXPECT_EQ(0, ping_checker.NumMisses()); 894 EXPECT_EQ(4, interceptor.GetHitCount()); 895 896 component_updater()->Stop(); 897} 898 899// Verify that a failed installation causes an install failure ping. 900TEST_F(ComponentUpdaterTest, CheckFailedInstallPing) { 901 std::map<std::string, std::string> map; 902 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 903 map.insert(std::pair<std::string, std::string>("eventresult", "\"0\"")); 904 map.insert(std::pair<std::string, std::string>("errorcode", "\"9\"")); 905 map.insert(std::pair<std::string, std::string>("previousversion", 906 "\"0.9\"")); 907 map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\"")); 908 PingChecker ping_checker(map); 909 URLRequestPostInterceptor post_interceptor(&ping_checker); 910 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 911 912 // This test installer reports installation failure. 913 class : public TestInstaller { 914 virtual bool Install(const base::DictionaryValue& manifest, 915 const base::FilePath& unpack_path) OVERRIDE { 916 ++install_count_; 917 base::DeleteFile(unpack_path, true); 918 return false; 919 } 920 } installer; 921 922 CrxComponent com; 923 RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), &installer); 924 925 // Start with 0.9, and attempt update to 1.0 926 const GURL expected_update_url_1( 927 "http://localhost/upd?extra=foo" 928 "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"); 929 930 interceptor.SetResponse(expected_update_url_1, 931 test_file("updatecheck_reply_1.xml")); 932 interceptor.SetResponse(GURL(expected_crx_url), 933 test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); 934 935 // Loop twice to issue two checks: (1) with original 0.9 version 936 // and (2), which should retry with 0.9. 937 test_configurator()->SetLoopCount(2); 938 component_updater()->Start(); 939 message_loop_.Run(); 940 941 // Loop once more, but expect no ping because a noupdate response is issued. 942 // This is necessary to clear out the fire-and-forget ping from the previous 943 // iteration. 944 interceptor.SetResponse(expected_update_url_1, 945 test_file("updatecheck_reply_noupdate.xml")); 946 test_configurator()->SetLoopCount(1); 947 component_updater()->Start(); 948 message_loop_.Run(); 949 950 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 951 EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count()); 952 953 EXPECT_EQ(2, ping_checker.NumHits()); 954 EXPECT_EQ(0, ping_checker.NumMisses()); 955 EXPECT_EQ(5, interceptor.GetHitCount()); 956 957 component_updater()->Stop(); 958} 959 960// Verify that we successfully propagate a patcher error. 961// ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx contains an incorrect 962// patching instruction that should fail. 963TEST_F(ComponentUpdaterTest, DifferentialUpdateFailErrorcode) { 964 std::map<std::string, std::string> map; 965 map.insert(std::pair<std::string, std::string>("eventtype", "\"3\"")); 966 map.insert(std::pair<std::string, std::string>("eventresult", "\"1\"")); 967 map.insert(std::pair<std::string, std::string>("diffresult", "\"0\"")); 968 map.insert(std::pair<std::string, std::string>("differrorcode", "\"14\"")); 969 map.insert(std::pair<std::string, std::string>("diffextracode1", "\"305\"")); 970 PingChecker ping_checker(map); 971 URLRequestPostInterceptor post_interceptor(&ping_checker); 972 content::URLLocalHostRequestPrepackagedInterceptor interceptor; 973 974 VersionedTestInstaller installer; 975 CrxComponent com; 976 RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), &installer); 977 978 const GURL expected_update_url_0( 979 "http://localhost/upd?extra=foo" 980 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D0.0%26fp%3D%26uc"); 981 const GURL expected_update_url_1( 982 "http://localhost/upd?extra=foo" 983 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D1%26uc"); 984 const GURL expected_update_url_2( 985 "http://localhost/upd?extra=foo" 986 "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc"); 987 const GURL expected_crx_url_1( 988 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"); 989 const GURL expected_crx_url_1_diff_2( 990 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"); 991 const GURL expected_crx_url_2( 992 "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"); 993 994 interceptor.SetResponse(expected_update_url_0, 995 test_file("updatecheck_diff_reply_1.xml")); 996 interceptor.SetResponse(expected_update_url_1, 997 test_file("updatecheck_diff_reply_2.xml")); 998 interceptor.SetResponse(expected_update_url_2, 999 test_file("updatecheck_diff_reply_3.xml")); 1000 interceptor.SetResponse(expected_crx_url_1, 1001 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx")); 1002 interceptor.SetResponse( 1003 expected_crx_url_1_diff_2, 1004 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx")); 1005 interceptor.SetResponse(expected_crx_url_2, 1006 test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx")); 1007 1008 test_configurator()->SetLoopCount(3); 1009 1010 component_updater()->Start(); 1011 message_loop_.Run(); 1012 1013 EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error()); 1014 EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count()); 1015 1016 EXPECT_EQ(1, ping_checker.NumHits()); 1017 EXPECT_EQ(1, ping_checker.NumMisses()); 1018 EXPECT_EQ(6, interceptor.GetHitCount()); 1019 1020 component_updater()->Stop(); 1021} 1022