component_updater_service_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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      base::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(const base::DictionaryValue& manifest,
148                       const base::FilePath& unpack_path) OVERRIDE {
149    ++install_count_;
150    return file_util::Delete(unpack_path, true);
151  }
152
153  int error() const { return error_; }
154
155  int install_count() const { return install_count_; }
156
157 private:
158  int error_;
159  int install_count_;
160};
161
162// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and
163// the RSA public key the following hash:
164const uint8 jebg_hash[] = {0x94,0x16,0x0b,0x6d,0x41,0x75,0xe9,0xec,0x8e,0xd5,
165                           0xfa,0x54,0xb0,0xd2,0xdd,0xa5,0x6e,0x05,0x6b,0xe8,
166                           0x73,0x47,0xf6,0xc4,0x11,0x9f,0xbc,0xb3,0x09,0xb3,
167                           0x5b,0x40};
168// component 2 has extension id "abagagagagagagagagagagagagagagag", and
169// the RSA public key the following hash:
170const uint8 abag_hash[] = {0x01,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
171                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
172                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
173                           0x06,0x01};
174
175const char expected_crx_url[] =
176    "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
177
178}  // namespace
179
180// Common fixture for all the component updater tests.
181class ComponentUpdaterTest : public testing::Test {
182 public:
183  enum TestComponents {
184    kTestComponent_abag,
185    kTestComponent_jebg
186  };
187
188  ComponentUpdaterTest() : test_config_(NULL) {
189    // The component updater instance under test.
190    test_config_ = new TestConfigurator;
191    component_updater_.reset(ComponentUpdateServiceFactory(test_config_));
192    test_config_->SetComponentUpdateService(component_updater_.get());
193    // The test directory is chrome/test/data/components.
194    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
195    test_data_dir_ = test_data_dir_.AppendASCII("components");
196
197    // Subscribe to all component updater notifications.
198    const int notifications[] = {
199      chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
200      chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
201      chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
202      chrome::NOTIFICATION_COMPONENT_UPDATE_READY
203    };
204
205    for (int ix = 0; ix != arraysize(notifications); ++ix) {
206      notification_tracker_.ListenFor(
207          notifications[ix], content::NotificationService::AllSources());
208    }
209    net::URLFetcher::SetEnableInterceptionForTests(true);
210  }
211
212  virtual ~ComponentUpdaterTest() {
213    net::URLFetcher::SetEnableInterceptionForTests(false);
214  }
215
216  virtual void TearDown() {
217    xmlCleanupGlobals();
218  }
219
220  ComponentUpdateService* component_updater() {
221    return component_updater_.get();
222  }
223
224  // Makes the full path to a component updater test file.
225  const base::FilePath test_file(const char* file) {
226    return test_data_dir_.AppendASCII(file);
227  }
228
229  TestNotificationTracker& notification_tracker() {
230    return notification_tracker_;
231  }
232
233  TestConfigurator* test_configurator() {
234    return test_config_;
235  }
236
237  ComponentUpdateService::Status RegisterComponent(CrxComponent* com,
238                                                   TestComponents component,
239                                                   const Version& version) {
240    if (component == kTestComponent_abag) {
241      com->name = "test_abag";
242      com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
243    } else {
244      com->name = "test_jebg";
245      com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
246    }
247    com->version = version;
248    TestInstaller* installer = new TestInstaller;
249    com->installer = installer;
250    test_installers_.push_back(installer);
251    return component_updater_->RegisterComponent(*com);
252  }
253
254 private:
255  scoped_ptr<ComponentUpdateService> component_updater_;
256  base::FilePath test_data_dir_;
257  TestNotificationTracker notification_tracker_;
258  TestConfigurator* test_config_;
259  // ComponentInstaller objects to delete after each test.
260  ScopedVector<TestInstaller> test_installers_;
261};
262
263// Verify that our test fixture work and the component updater can
264// be created and destroyed with no side effects.
265TEST_F(ComponentUpdaterTest, VerifyFixture) {
266  EXPECT_TRUE(component_updater() != NULL);
267  EXPECT_EQ(0ul, notification_tracker().size());
268}
269
270// Verify that the component updater can be caught in a quick
271// start-shutdown situation. Failure of this test will be a crash. Also
272// if there is no work to do, there are no notifications generated.
273TEST_F(ComponentUpdaterTest, StartStop) {
274  base::MessageLoop message_loop;
275  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
276
277  component_updater()->Start();
278  message_loop.RunUntilIdle();
279  component_updater()->Stop();
280
281  EXPECT_EQ(0ul, notification_tracker().size());
282}
283
284// Verify that when the server has no updates, we go back to sleep and
285// the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications
286// are generated.
287TEST_F(ComponentUpdaterTest, CheckCrxSleep) {
288  base::MessageLoop message_loop;
289  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
290  content::TestBrowserThread file_thread(BrowserThread::FILE);
291  content::TestBrowserThread io_thread(BrowserThread::IO);
292
293  io_thread.StartIOThread();
294  file_thread.Start();
295
296  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
297
298  CrxComponent com;
299  EXPECT_EQ(ComponentUpdateService::kOk,
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  base::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::URLLocalHostRequestPrepackagedInterceptor 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  base::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::URLLocalHostRequestPrepackagedInterceptor 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  base::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::URLLocalHostRequestPrepackagedInterceptor 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  base::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::URLLocalHostRequestPrepackagedInterceptor 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
657// Verify that a previously registered component can get re-registered
658// with a different version.
659TEST_F(ComponentUpdaterTest, CheckReRegistration) {
660  base::MessageLoop message_loop;
661  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
662  content::TestBrowserThread file_thread(BrowserThread::FILE);
663  content::TestBrowserThread io_thread(BrowserThread::IO);
664
665  io_thread.StartIOThread();
666  file_thread.Start();
667
668  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
669
670  CrxComponent com1;
671  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"));
672  CrxComponent com2;
673  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"));
674
675  // Start with 0.9, and update to 1.0
676  const GURL expected_update_url_1(
677      "http://localhost/upd?extra=foo&x=id%3D"
678      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
679      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
680
681  const GURL expected_update_url_2(
682      "http://localhost/upd?extra=foo&x=id%3D"
683      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
684      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc");
685
686  interceptor.SetResponse(expected_update_url_1,
687                          test_file("updatecheck_reply_1.xml"));
688  interceptor.SetResponse(expected_update_url_2,
689                          test_file("updatecheck_reply_1.xml"));
690  interceptor.SetResponse(GURL(expected_crx_url),
691                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
692
693  // Loop twice to issue two checks: (1) with original 0.9 version
694  // and (2) with the updated 1.0 version.
695  test_configurator()->SetLoopCount(2);
696
697  component_updater()->Start();
698  message_loop.Run();
699
700  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
701  EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
702  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
703  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
704
705  EXPECT_EQ(3, interceptor.GetHitCount());
706
707  ASSERT_EQ(5ul, notification_tracker().size());
708
709  TestNotificationTracker::Event ev0 = notification_tracker().at(0);
710  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
711
712  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
713  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
714
715  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
716  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
717
718  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
719  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
720
721  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
722  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
723
724  // Now re-register, pretending to be an even newer version (2.2)
725  component_updater()->Stop();
726  EXPECT_EQ(ComponentUpdateService::kReplaced,
727            RegisterComponent(&com1, kTestComponent_jebg, Version("2.2")));
728
729  // Check that we send out 2.2 as our version.
730  // Interceptor's hit count should go up by 1.
731  const GURL expected_update_url_3(
732      "http://localhost/upd?extra=foo&x=id%3D"
733      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D2.2%26uc&x=id%3D"
734      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
735
736  interceptor.SetResponse(expected_update_url_3,
737                          test_file("updatecheck_reply_1.xml"));
738
739  notification_tracker().Reset();
740
741  // Loop once just to notice the check happening with the re-register version.
742  test_configurator()->SetLoopCount(1);
743  component_updater()->Start();
744  message_loop.Run();
745
746  ASSERT_EQ(2ul, notification_tracker().size());
747
748  ev0 = notification_tracker().at(0);
749  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
750
751  ev1 = notification_tracker().at(1);
752  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
753
754  EXPECT_EQ(4, interceptor.GetHitCount());
755
756  // The test harness's Register() function creates a new installer,
757  // so the counts go back to 0.
758  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
759  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
760  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
761  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
762
763  component_updater()->Stop();
764}
765