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