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