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