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