component_updater_service_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/component_updater_service.h"
6
7#include <list>
8#include <utility>
9
10#include "base/compiler_specific.h"
11#include "base/file_util.h"
12#include "base/files/file_path.h"
13#include "base/memory/scoped_vector.h"
14#include "base/message_loop.h"
15#include "base/path_service.h"
16#include "base/values.h"
17#include "chrome/common/chrome_notification_types.h"
18#include "chrome/common/chrome_paths.h"
19#include "content/public/browser/notification_observer.h"
20#include "content/public/browser/notification_service.h"
21#include "content/public/test/test_browser_thread.h"
22#include "content/public/test/test_notification_tracker.h"
23#include "content/test/net/url_request_prepackaged_interceptor.h"
24#include "googleurl/src/gurl.h"
25#include "libxml/globals.h"
26#include "net/url_request/url_fetcher.h"
27#include "net/url_request/url_request_test_util.h"
28#include "testing/gtest/include/gtest/gtest.h"
29
30using content::BrowserThread;
31using content::TestNotificationTracker;
32
33namespace {
34// Overrides some of the component updater behaviors so it is easier to test
35// and loops faster. In actual usage it takes hours do to a full cycle.
36class TestConfigurator : public ComponentUpdateService::Configurator {
37 public:
38  TestConfigurator()
39      : times_(1), recheck_time_(0), ondemand_time_(0), cus_(NULL) {
40  }
41
42  virtual int InitialDelay() OVERRIDE { return 0; }
43
44  typedef std::pair<CrxComponent*, int> CheckAtLoopCount;
45
46  virtual int NextCheckDelay() OVERRIDE {
47    // This is called when a new full cycle of checking for updates is going
48    // to happen. In test we normally only test one cycle so it is a good
49    // time to break from the test messageloop Run() method so the test can
50    // finish.
51    if (--times_ <= 0) {
52      MessageLoop::current()->Quit();
53      return 0;
54
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(*i->first);
63        i = components_to_check_.erase(i);
64      } else {
65        ++i;
66      }
67    }
68    return 1;
69  }
70
71  virtual int StepDelay() OVERRIDE {
72    return 0;
73  }
74
75  virtual int MinimumReCheckWait() OVERRIDE {
76    return recheck_time_;
77  }
78
79  virtual int OnDemandDelay() OVERRIDE {
80    return ondemand_time_;
81  }
82
83  virtual GURL UpdateUrl(CrxComponent::UrlSource source) OVERRIDE {
84    switch (source) {
85      case CrxComponent::BANDAID:
86        return GURL("http://localhost/upd");
87      case CrxComponent::CWS_PUBLIC:
88        return GURL("http://localhost/cws");
89      default:
90        return GURL("http://wronghost/bad");
91    };
92  }
93
94  virtual const char* ExtraRequestParams() OVERRIDE { return "extra=foo"; }
95
96  virtual size_t UrlSizeLimit() OVERRIDE { return 256; }
97
98  virtual net::URLRequestContextGetter* RequestContext() OVERRIDE {
99    return new net::TestURLRequestContextGetter(
100        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
101  }
102
103  // Don't use the utility process to decode files.
104  virtual bool InProcess() OVERRIDE { return true; }
105
106  virtual void OnEvent(Events event, int extra) OVERRIDE { }
107
108  // Set how many update checks are called, the default value is just once.
109  void SetLoopCount(int times) { times_ = times; }
110
111  void SetRecheckTime(int seconds) {
112    recheck_time_ = seconds;
113  }
114
115  void SetOnDemandTime(int seconds) {
116    ondemand_time_ = seconds;
117  }
118
119  void AddComponentToCheck(CrxComponent* com, int at_loop_iter) {
120    components_to_check_.push_back(std::make_pair(com, at_loop_iter));
121  }
122
123  void SetComponentUpdateService(ComponentUpdateService* cus) {
124    cus_ = cus;
125  }
126
127 private:
128  int times_;
129  int recheck_time_;
130  int ondemand_time_;
131
132  std::list<CheckAtLoopCount> components_to_check_;
133  ComponentUpdateService* cus_;
134};
135
136class TestInstaller : public ComponentInstaller {
137 public :
138  explicit TestInstaller()
139      : error_(0), install_count_(0) {
140  }
141
142  virtual void OnUpdateError(int error) OVERRIDE {
143    EXPECT_NE(0, error);
144    error_ = error;
145  }
146
147  virtual bool Install(base::DictionaryValue* manifest,
148                       const base::FilePath& unpack_path) OVERRIDE {
149    ++install_count_;
150    delete manifest;
151    return file_util::Delete(unpack_path, true);
152  }
153
154  int error() const { return error_; }
155
156  int install_count() const { return install_count_; }
157
158 private:
159  int error_;
160  int install_count_;
161};
162
163// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and
164// the RSA public key the following hash:
165const uint8 jebg_hash[] = {0x94,0x16,0x0b,0x6d,0x41,0x75,0xe9,0xec,0x8e,0xd5,
166                           0xfa,0x54,0xb0,0xd2,0xdd,0xa5,0x6e,0x05,0x6b,0xe8,
167                           0x73,0x47,0xf6,0xc4,0x11,0x9f,0xbc,0xb3,0x09,0xb3,
168                           0x5b,0x40};
169// component 2 has extension id "abagagagagagagagagagagagagagagag", and
170// the RSA public key the following hash:
171const uint8 abag_hash[] = {0x01,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
172                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
173                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
174                           0x06,0x01};
175
176const char expected_crx_url[] =
177    "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
178
179}  // namespace
180
181// Common fixture for all the component updater tests.
182class ComponentUpdaterTest : public testing::Test {
183 public:
184  enum TestComponents {
185    kTestComponent_abag,
186    kTestComponent_jebg
187  };
188
189  ComponentUpdaterTest() : component_updater_(NULL), test_config_(NULL) {
190    // The component updater instance under test.
191    test_config_ = new TestConfigurator;
192    component_updater_.reset(ComponentUpdateServiceFactory(test_config_));
193    test_config_->SetComponentUpdateService(component_updater_.get());
194    // The test directory is chrome/test/data/components.
195    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
196    test_data_dir_ = test_data_dir_.AppendASCII("components");
197
198    // Subscribe to all component updater notifications.
199    const int notifications[] = {
200      chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
201      chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
202      chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
203      chrome::NOTIFICATION_COMPONENT_UPDATE_READY
204    };
205
206    for (int ix = 0; ix != arraysize(notifications); ++ix) {
207      notification_tracker_.ListenFor(
208          notifications[ix], content::NotificationService::AllSources());
209    }
210    net::URLFetcher::SetEnableInterceptionForTests(true);
211  }
212
213  virtual ~ComponentUpdaterTest() {
214    net::URLFetcher::SetEnableInterceptionForTests(false);
215  }
216
217  virtual void TearDown() {
218    xmlCleanupGlobals();
219  }
220
221  ComponentUpdateService* component_updater() {
222    return component_updater_.get();
223  }
224
225  // Makes the full path to a component updater test file.
226  const base::FilePath test_file(const char* file) {
227    return test_data_dir_.AppendASCII(file);
228  }
229
230  TestNotificationTracker& notification_tracker() {
231    return notification_tracker_;
232  }
233
234  TestConfigurator* test_configurator() {
235    return test_config_;
236  }
237
238  void RegisterComponent(CrxComponent* com,
239                         TestComponents component,
240                         const Version& version) {
241    if (component == kTestComponent_abag) {
242      com->name = "test_abag";
243      com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
244    } else {
245      com->name = "test_jebg";
246      com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
247    }
248    com->version = version;
249    TestInstaller* installer = new TestInstaller;
250    com->installer = installer;
251    test_installers_.push_back(installer);
252    component_updater_->RegisterComponent(*com);
253  }
254
255 private:
256  scoped_ptr<ComponentUpdateService> component_updater_;
257  base::FilePath test_data_dir_;
258  TestNotificationTracker notification_tracker_;
259  TestConfigurator* test_config_;
260  // ComponentInstaller objects to delete after each test.
261  ScopedVector<TestInstaller> test_installers_;
262};
263
264// Verify that our test fixture work and the component updater can
265// be created and destroyed with no side effects.
266TEST_F(ComponentUpdaterTest, VerifyFixture) {
267  EXPECT_TRUE(component_updater() != NULL);
268  EXPECT_EQ(0ul, notification_tracker().size());
269}
270
271// Verify that the component updater can be caught in a quick
272// start-shutdown situation. Failure of this test will be a crash. Also
273// if there is no work to do, there are no notifications generated.
274TEST_F(ComponentUpdaterTest, StartStop) {
275  MessageLoop message_loop;
276  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
277
278  component_updater()->Start();
279  message_loop.RunUntilIdle();
280  component_updater()->Stop();
281
282  EXPECT_EQ(0ul, notification_tracker().size());
283}
284
285// Verify that when the server has no updates, we go back to sleep and
286// the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications
287// are generated.
288TEST_F(ComponentUpdaterTest, CheckCrxSleep) {
289  MessageLoop message_loop;
290  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
291  content::TestBrowserThread file_thread(BrowserThread::FILE);
292  content::TestBrowserThread io_thread(BrowserThread::IO);
293
294  io_thread.StartIOThread();
295  file_thread.Start();
296
297  content::URLRequestPrepackagedInterceptor interceptor;
298
299  CrxComponent com;
300  RegisterComponent(&com, kTestComponent_abag, Version("1.1"));
301
302  const GURL expected_update_url(
303      "http://localhost/upd?extra=foo&x=id%3D"
304      "abagagagagagagagagagagagagagagag%26v%3D1.1%26uc");
305
306  interceptor.SetResponse(expected_update_url,
307                          test_file("updatecheck_reply_1.xml"));
308
309  // We loop twice, but there are no updates so we expect two sleep messages.
310  test_configurator()->SetLoopCount(2);
311  component_updater()->Start();
312
313  ASSERT_EQ(1ul, notification_tracker().size());
314  TestNotificationTracker::Event ev1 = notification_tracker().at(0);
315  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev1.type);
316
317  message_loop.Run();
318
319  ASSERT_EQ(3ul, notification_tracker().size());
320  TestNotificationTracker::Event ev2 = notification_tracker().at(1);
321  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
322  TestNotificationTracker::Event ev3 = notification_tracker().at(2);
323  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
324  EXPECT_EQ(2, interceptor.GetHitCount());
325
326  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
327  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
328
329  component_updater()->Stop();
330
331  // Loop twice again but this case we simulate a server error by returning
332  // an empty file.
333
334  interceptor.SetResponse(expected_update_url,
335                          test_file("updatecheck_reply_empty"));
336
337  notification_tracker().Reset();
338  test_configurator()->SetLoopCount(2);
339  component_updater()->Start();
340
341  message_loop.Run();
342
343  ASSERT_EQ(3ul, notification_tracker().size());
344  ev1 = notification_tracker().at(0);
345  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev1.type);
346  ev2 = notification_tracker().at(1);
347  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
348  ev3 = notification_tracker().at(2);
349  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
350  EXPECT_EQ(4, interceptor.GetHitCount());
351
352  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
353  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
354
355  component_updater()->Stop();
356}
357
358// Verify that we can check for updates and install one component. Besides
359// the notifications above NOTIFICATION_COMPONENT_UPDATE_FOUND and
360// NOTIFICATION_COMPONENT_UPDATE_READY should have been fired. We do two loops
361// so the second time around there should be nothing left to do.
362// We also check that only 3 network requests are issued:
363// 1- manifest check
364// 2- download crx
365// 3- second manifest check.
366TEST_F(ComponentUpdaterTest, InstallCrx) {
367  MessageLoop message_loop;
368  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
369  content::TestBrowserThread file_thread(BrowserThread::FILE);
370  content::TestBrowserThread io_thread(BrowserThread::IO);
371
372  io_thread.StartIOThread();
373  file_thread.Start();
374
375  content::URLRequestPrepackagedInterceptor interceptor;
376
377  CrxComponent com1;
378  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"));
379  CrxComponent com2;
380  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"));
381
382  const GURL expected_update_url_1(
383      "http://localhost/upd?extra=foo&x=id%3D"
384      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
385      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
386
387  const GURL expected_update_url_2(
388      "http://localhost/upd?extra=foo&x=id%3D"
389      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
390      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc");
391
392  interceptor.SetResponse(expected_update_url_1,
393                          test_file("updatecheck_reply_1.xml"));
394  interceptor.SetResponse(expected_update_url_2,
395                          test_file("updatecheck_reply_1.xml"));
396  interceptor.SetResponse(GURL(expected_crx_url),
397                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
398
399  test_configurator()->SetLoopCount(2);
400
401  component_updater()->Start();
402  message_loop.Run();
403
404  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
405  EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
406  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
407  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
408
409  EXPECT_EQ(3, interceptor.GetHitCount());
410
411  ASSERT_EQ(5ul, notification_tracker().size());
412
413  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
414  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
415
416  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
417  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
418
419  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
420  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
421
422  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
423  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
424
425  component_updater()->Stop();
426}
427
428// This test is like the above InstallCrx but the second component
429// has a different source. In this case there would be two manifest
430// checks to different urls, each only containing one component.
431TEST_F(ComponentUpdaterTest, InstallCrxTwoSources) {
432  MessageLoop message_loop;
433  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
434  content::TestBrowserThread file_thread(BrowserThread::FILE);
435  content::TestBrowserThread io_thread(BrowserThread::IO);
436
437  io_thread.StartIOThread();
438  file_thread.Start();
439
440  content::URLRequestPrepackagedInterceptor interceptor;
441
442  CrxComponent com1;
443  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"));
444  CrxComponent com2;
445  com2.source = CrxComponent::CWS_PUBLIC;
446  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"));
447
448  const GURL expected_update_url_1(
449      "http://localhost/upd?extra=foo&x=id%3D"
450      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
451
452  const GURL expected_update_url_2(
453      "http://localhost/cws?extra=foo&x=id%3D"
454      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
455
456  interceptor.SetResponse(expected_update_url_1,
457                          test_file("updatecheck_reply_3.xml"));
458  interceptor.SetResponse(expected_update_url_2,
459                          test_file("updatecheck_reply_1.xml"));
460  interceptor.SetResponse(GURL(expected_crx_url),
461                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
462
463  test_configurator()->SetLoopCount(3);
464
465  // We have to set SetRecheckTime to something bigger than 0 or else the
466  // component updater will keep re-checking the 'abag' component because
467  // the default source pre-empts the other sources.
468  test_configurator()->SetRecheckTime(60*60);
469
470  component_updater()->Start();
471  message_loop.Run();
472
473  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
474  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
475  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
476  EXPECT_EQ(1, static_cast<TestInstaller*>(com2.installer)->install_count());
477
478  EXPECT_EQ(3, interceptor.GetHitCount());
479
480  ASSERT_EQ(6ul, notification_tracker().size());
481
482  TestNotificationTracker::Event ev0 = notification_tracker().at(1);
483  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev0.type);
484
485  TestNotificationTracker::Event ev1 = notification_tracker().at(2);
486  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
487
488  TestNotificationTracker::Event ev2 = notification_tracker().at(3);
489  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
490
491  TestNotificationTracker::Event ev3 = notification_tracker().at(4);
492  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
493
494  TestNotificationTracker::Event ev4 = notification_tracker().at(5);
495  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
496
497  component_updater()->Stop();
498}
499
500// This test checks that the "prodversionmin" value is handled correctly. In
501// particular there should not be an install because the minimum product
502// version is much higher than of chrome.
503TEST_F(ComponentUpdaterTest, ProdVersionCheck) {
504  MessageLoop message_loop;
505  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
506  content::TestBrowserThread file_thread(BrowserThread::FILE);
507  content::TestBrowserThread io_thread(BrowserThread::IO);
508
509  io_thread.StartIOThread();
510  file_thread.Start();
511
512  content::URLRequestPrepackagedInterceptor interceptor;
513
514  CrxComponent com;
515  RegisterComponent(&com, kTestComponent_jebg, Version("0.9"));
516
517  const GURL expected_update_url(
518      "http://localhost/upd?extra=foo&x=id%3D"
519      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
520
521  interceptor.SetResponse(expected_update_url,
522                          test_file("updatecheck_reply_2.xml"));
523  interceptor.SetResponse(GURL(expected_crx_url),
524                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
525
526  test_configurator()->SetLoopCount(1);
527  component_updater()->Start();
528  message_loop.Run();
529
530  EXPECT_EQ(1, interceptor.GetHitCount());
531  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
532  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
533
534  component_updater()->Stop();
535}
536
537// Test that a ping for an update check can cause installs.
538// Here is the timeline:
539//  - First loop: we return a reply that indicates no update, so
540//    nothing happens.
541//  - We ping.
542//  - This triggers a second loop, which has a reply that triggers an install.
543TEST_F(ComponentUpdaterTest, CheckForUpdateSoon) {
544  MessageLoop message_loop;
545  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
546  content::TestBrowserThread file_thread(BrowserThread::FILE);
547  content::TestBrowserThread io_thread(BrowserThread::IO);
548
549  io_thread.StartIOThread();
550  file_thread.Start();
551
552  content::URLRequestPrepackagedInterceptor interceptor;
553
554  CrxComponent com1;
555  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"));
556  CrxComponent com2;
557  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"));
558
559  const GURL expected_update_url_1(
560      "http://localhost/upd?extra=foo&x=id%3D"
561      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
562      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
563
564  const GURL expected_update_url_2(
565      "http://localhost/upd?extra=foo&x=id%3D"
566      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
567      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
568
569  interceptor.SetResponse(expected_update_url_1,
570                          test_file("updatecheck_reply_empty"));
571  interceptor.SetResponse(expected_update_url_2,
572                          test_file("updatecheck_reply_1.xml"));
573  interceptor.SetResponse(GURL(expected_crx_url),
574                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
575  // Test success.
576  test_configurator()->SetLoopCount(2);
577  test_configurator()->AddComponentToCheck(&com2, 1);
578  component_updater()->Start();
579  message_loop.Run();
580
581  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
582  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
583  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
584  EXPECT_EQ(1, static_cast<TestInstaller*>(com2.installer)->install_count());
585
586  EXPECT_EQ(3, interceptor.GetHitCount());
587
588  ASSERT_EQ(5ul, notification_tracker().size());
589
590  TestNotificationTracker::Event ev0= notification_tracker().at(0);
591  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
592
593  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
594  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
595
596  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
597  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev2.type);
598
599  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
600  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev3.type);
601
602  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
603  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
604
605  // Also check what happens if previous check too soon.
606  test_configurator()->SetOnDemandTime(60 * 60);
607  EXPECT_EQ(ComponentUpdateService::kError,
608            component_updater()->CheckForUpdateSoon(com2));
609  // Okay, now reset to 0 for the other tests.
610  test_configurator()->SetOnDemandTime(0);
611  component_updater()->Stop();
612
613  // Test a few error cases. NOTE: We don't have callbacks for
614  // when the updates failed yet.
615  const GURL expected_update_url_3(
616      "http://localhost/upd?extra=foo&x=id%3D"
617      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc&x=id%3D"
618      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
619
620  // No update: error from no server response
621  interceptor.SetResponse(expected_update_url_3,
622                          test_file("updatecheck_reply_empty"));
623  notification_tracker().Reset();
624  test_configurator()->SetLoopCount(1);
625  component_updater()->Start();
626  EXPECT_EQ(ComponentUpdateService::kOk,
627            component_updater()->CheckForUpdateSoon(com2));
628
629  message_loop.Run();
630
631  ASSERT_EQ(2ul, notification_tracker().size());
632  ev0 = notification_tracker().at(0);
633  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
634  ev1 = notification_tracker().at(1);
635  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
636  component_updater()->Stop();
637
638  // No update: already updated to 1.0 so nothing new
639  interceptor.SetResponse(expected_update_url_3,
640                          test_file("updatecheck_reply_1.xml"));
641  notification_tracker().Reset();
642  test_configurator()->SetLoopCount(1);
643  component_updater()->Start();
644  EXPECT_EQ(ComponentUpdateService::kOk,
645            component_updater()->CheckForUpdateSoon(com2));
646
647  message_loop.Run();
648
649  ASSERT_EQ(2ul, notification_tracker().size());
650  ev0 = notification_tracker().at(0);
651  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
652  ev1 = notification_tracker().at(1);
653  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
654  component_updater()->Stop();
655}
656