component_updater_service_unittest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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 <list>
6#include <utility>
7#include "base/compiler_specific.h"
8#include "base/file_util.h"
9#include "base/files/file_path.h"
10#include "base/memory/scoped_vector.h"
11#include "base/message_loop/message_loop.h"
12#include "base/path_service.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/stringprintf.h"
15#include "base/values.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/component_updater/component_updater_service.h"
18#include "chrome/browser/component_updater/test/component_patcher_mock.h"
19#include "chrome/browser/component_updater/test/component_updater_service_unittest.h"
20#include "chrome/browser/component_updater/test/test_installer.h"
21#include "chrome/common/chrome_paths.h"
22#include "content/public/browser/notification_observer.h"
23#include "content/public/browser/notification_service.h"
24#include "content/public/test/test_browser_thread.h"
25#include "content/public/test/test_notification_tracker.h"
26#include "content/test/net/url_request_prepackaged_interceptor.h"
27#include "libxml/globals.h"
28#include "net/base/upload_bytes_element_reader.h"
29#include "net/url_request/url_fetcher.h"
30#include "net/url_request/url_request.h"
31#include "net/url_request/url_request_filter.h"
32#include "net/url_request/url_request_simple_job.h"
33#include "net/url_request/url_request_test_util.h"
34#include "testing/gtest/include/gtest/gtest.h"
35#include "url/gurl.h"
36
37using content::BrowserThread;
38using content::TestNotificationTracker;
39
40TestConfigurator::TestConfigurator()
41    : times_(1), recheck_time_(0), ondemand_time_(0), cus_(NULL) {
42}
43
44TestConfigurator::~TestConfigurator() {
45}
46
47int TestConfigurator::InitialDelay() { return 0; }
48
49int TestConfigurator::NextCheckDelay() {
50  // This is called when a new full cycle of checking for updates is going
51  // to happen. In test we normally only test one cycle so it is a good
52  // time to break from the test messageloop Run() method so the test can
53  // finish.
54  if (--times_ <= 0) {
55    base::MessageLoop::current()->Quit();
56    return 0;
57  }
58
59  // Look for checks to issue in the middle of the loop.
60  for (std::list<CheckAtLoopCount>::iterator
61           i = components_to_check_.begin();
62       i != components_to_check_.end(); ) {
63    if (i->second == times_) {
64      cus_->CheckForUpdateSoon(*i->first);
65      i = components_to_check_.erase(i);
66    } else {
67      ++i;
68    }
69  }
70  return 1;
71}
72
73int TestConfigurator::StepDelay() {
74  return 0;
75}
76
77int TestConfigurator::MinimumReCheckWait() {
78  return recheck_time_;
79}
80
81int TestConfigurator::OnDemandDelay() {
82  return ondemand_time_;
83}
84
85GURL TestConfigurator::UpdateUrl() {
86  return GURL("http://localhost/upd");
87}
88
89const char* TestConfigurator::ExtraRequestParams() { return "extra=foo"; }
90
91size_t TestConfigurator::UrlSizeLimit() { return 256; }
92
93net::URLRequestContextGetter* TestConfigurator::RequestContext() {
94  return new net::TestURLRequestContextGetter(
95      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
96}
97
98// Don't use the utility process to decode files.
99bool TestConfigurator::InProcess() { return true; }
100
101void TestConfigurator::OnEvent(Events event, int extra) { }
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() : test_config_(NULL) {
132  // The component updater instance under test.
133  test_config_ = new TestConfigurator;
134  component_updater_.reset(ComponentUpdateServiceFactory(test_config_));
135  test_config_->SetComponentUpdateService(component_updater_.get());
136  // The test directory is chrome/test/data/components.
137  PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
138  test_data_dir_ = test_data_dir_.AppendASCII("components");
139
140  // Subscribe to all component updater notifications.
141  const int notifications[] = {
142    chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
143    chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
144    chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
145    chrome::NOTIFICATION_COMPONENT_UPDATE_READY
146  };
147
148  for (int ix = 0; ix != arraysize(notifications); ++ix) {
149    notification_tracker_.ListenFor(
150        notifications[ix], content::NotificationService::AllSources());
151  }
152  net::URLFetcher::SetEnableInterceptionForTests(true);
153}
154
155ComponentUpdaterTest::~ComponentUpdaterTest() {
156  net::URLFetcher::SetEnableInterceptionForTests(false);
157}
158
159void ComponentUpdaterTest::TearDown() {
160  xmlCleanupGlobals();
161}
162
163ComponentUpdateService* ComponentUpdaterTest::component_updater() {
164  return component_updater_.get();
165}
166
167  // Makes the full path to a component updater test file.
168const base::FilePath ComponentUpdaterTest::test_file(const char* file) {
169  return test_data_dir_.AppendASCII(file);
170}
171
172TestNotificationTracker& ComponentUpdaterTest::notification_tracker() {
173  return notification_tracker_;
174}
175
176TestConfigurator* ComponentUpdaterTest::test_configurator() {
177  return test_config_;
178}
179
180ComponentUpdateService::Status ComponentUpdaterTest::RegisterComponent(
181    CrxComponent* com,
182    TestComponents component,
183    const Version& version,
184    TestInstaller* installer) {
185  if (component == kTestComponent_abag) {
186    com->name = "test_abag";
187    com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
188  } else if (component == kTestComponent_jebg) {
189    com->name = "test_jebg";
190    com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
191  } else {
192    com->name = "test_ihfo";
193    com->pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
194  }
195  com->version = version;
196  com->installer = installer;
197  return component_updater_->RegisterComponent(*com);
198}
199
200// Verify that our test fixture work and the component updater can
201// be created and destroyed with no side effects.
202TEST_F(ComponentUpdaterTest, VerifyFixture) {
203  EXPECT_TRUE(component_updater() != NULL);
204  EXPECT_EQ(0ul, notification_tracker().size());
205}
206
207// Verify that the component updater can be caught in a quick
208// start-shutdown situation. Failure of this test will be a crash. Also
209// if there is no work to do, there are no notifications generated.
210TEST_F(ComponentUpdaterTest, StartStop) {
211  base::MessageLoop message_loop;
212  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
213
214  component_updater()->Start();
215  message_loop.RunUntilIdle();
216  component_updater()->Stop();
217
218  EXPECT_EQ(0ul, notification_tracker().size());
219}
220
221// Verify that when the server has no updates, we go back to sleep and
222// the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications
223// are generated.
224TEST_F(ComponentUpdaterTest, CheckCrxSleep) {
225  base::MessageLoop message_loop;
226  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
227  content::TestBrowserThread file_thread(BrowserThread::FILE);
228  content::TestBrowserThread io_thread(BrowserThread::IO);
229
230  io_thread.StartIOThread();
231  file_thread.Start();
232
233  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
234
235  TestInstaller installer;
236  CrxComponent com;
237  EXPECT_EQ(ComponentUpdateService::kOk,
238            RegisterComponent(&com,
239                              kTestComponent_abag,
240                              Version("1.1"),
241                              &installer));
242
243  const GURL expected_update_url(
244      "http://localhost/upd?extra=foo"
245      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D1.1%26fp%3D%26uc");
246
247  interceptor.SetResponse(expected_update_url,
248                          test_file("updatecheck_reply_1.xml"));
249
250  // We loop twice, but there are no updates so we expect two sleep messages.
251  test_configurator()->SetLoopCount(2);
252  component_updater()->Start();
253
254  ASSERT_EQ(1ul, notification_tracker().size());
255  TestNotificationTracker::Event ev1 = notification_tracker().at(0);
256  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev1.type);
257
258  message_loop.Run();
259
260  ASSERT_EQ(3ul, notification_tracker().size());
261  TestNotificationTracker::Event ev2 = notification_tracker().at(1);
262  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
263  TestNotificationTracker::Event ev3 = notification_tracker().at(2);
264  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
265  EXPECT_EQ(2, interceptor.GetHitCount());
266
267  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
268  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
269
270  component_updater()->Stop();
271
272  // Loop twice again but this case we simulate a server error by returning
273  // an empty file.
274
275  interceptor.SetResponse(expected_update_url,
276                          test_file("updatecheck_reply_empty"));
277
278  notification_tracker().Reset();
279  test_configurator()->SetLoopCount(2);
280  component_updater()->Start();
281
282  message_loop.Run();
283
284  ASSERT_EQ(3ul, notification_tracker().size());
285  ev1 = notification_tracker().at(0);
286  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev1.type);
287  ev2 = notification_tracker().at(1);
288  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
289  ev3 = notification_tracker().at(2);
290  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev2.type);
291  EXPECT_EQ(4, interceptor.GetHitCount());
292
293  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
294  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
295
296  component_updater()->Stop();
297}
298
299// Verify that we can check for updates and install one component. Besides
300// the notifications above NOTIFICATION_COMPONENT_UPDATE_FOUND and
301// NOTIFICATION_COMPONENT_UPDATE_READY should have been fired. We do two loops
302// so the second time around there should be nothing left to do.
303// We also check that only 3 network requests are issued:
304// 1- manifest check
305// 2- download crx
306// 3- second manifest check.
307TEST_F(ComponentUpdaterTest, InstallCrx) {
308  base::MessageLoop message_loop;
309  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
310  content::TestBrowserThread file_thread(BrowserThread::FILE);
311  content::TestBrowserThread io_thread(BrowserThread::IO);
312
313  io_thread.StartIOThread();
314  file_thread.Start();
315
316  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
317
318  TestInstaller installer1;
319  CrxComponent com1;
320  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1);
321  TestInstaller installer2;
322  CrxComponent com2;
323  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2);
324
325  const GURL expected_update_url_1(
326      "http://localhost/upd?extra=foo"
327      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
328      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
329
330  const GURL expected_update_url_2(
331      "http://localhost/upd?extra=foo"
332      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
333      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc");
334
335  interceptor.SetResponse(expected_update_url_1,
336                          test_file("updatecheck_reply_1.xml"));
337  interceptor.SetResponse(expected_update_url_2,
338                          test_file("updatecheck_reply_1.xml"));
339  interceptor.SetResponse(GURL(expected_crx_url),
340                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
341
342  test_configurator()->SetLoopCount(2);
343
344  component_updater()->Start();
345  message_loop.Run();
346
347  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
348  EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
349  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
350  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
351
352  EXPECT_EQ(3, interceptor.GetHitCount());
353
354  ASSERT_EQ(5ul, notification_tracker().size());
355
356  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
357  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
358
359  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
360  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
361
362  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
363  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
364
365  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
366  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
367
368  component_updater()->Stop();
369}
370
371// This test checks that the "prodversionmin" value is handled correctly. In
372// particular there should not be an install because the minimum product
373// version is much higher than of chrome.
374TEST_F(ComponentUpdaterTest, ProdVersionCheck) {
375  base::MessageLoop message_loop;
376  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
377  content::TestBrowserThread file_thread(BrowserThread::FILE);
378  content::TestBrowserThread io_thread(BrowserThread::IO);
379
380  io_thread.StartIOThread();
381  file_thread.Start();
382
383  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
384
385  TestInstaller installer;
386  CrxComponent com;
387  RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), &installer);
388
389  const GURL expected_update_url(
390      "http://localhost/upd?extra=foo&x=id%3D"
391      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc");
392
393  interceptor.SetResponse(expected_update_url,
394                          test_file("updatecheck_reply_2.xml"));
395  interceptor.SetResponse(GURL(expected_crx_url),
396                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
397
398  test_configurator()->SetLoopCount(1);
399  component_updater()->Start();
400  message_loop.Run();
401
402  EXPECT_EQ(1, interceptor.GetHitCount());
403  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
404  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
405
406  component_updater()->Stop();
407}
408
409// Test that a ping for an update check can cause installs.
410// Here is the timeline:
411//  - First loop: we return a reply that indicates no update, so
412//    nothing happens.
413//  - We ping.
414//  - This triggers a second loop, which has a reply that triggers an install.
415TEST_F(ComponentUpdaterTest, CheckForUpdateSoon) {
416  base::MessageLoop message_loop;
417  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
418  content::TestBrowserThread file_thread(BrowserThread::FILE);
419  content::TestBrowserThread io_thread(BrowserThread::IO);
420
421  io_thread.StartIOThread();
422  file_thread.Start();
423
424  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
425
426  TestInstaller installer1;
427  CrxComponent com1;
428  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"), &installer1);
429  TestInstaller installer2;
430  CrxComponent com2;
431  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"), &installer2);
432
433  const GURL expected_update_url_1(
434      "http://localhost/upd?extra=foo"
435      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
436      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc");
437
438  const GURL expected_update_url_2(
439      "http://localhost/upd?extra=foo"
440      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
441      "%26installsource%3Dondemand"
442      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
443
444  interceptor.SetResponse(expected_update_url_1,
445                          test_file("updatecheck_reply_empty"));
446  interceptor.SetResponse(expected_update_url_2,
447                          test_file("updatecheck_reply_1.xml"));
448  interceptor.SetResponse(GURL(expected_crx_url),
449                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
450  // Test success.
451  test_configurator()->SetLoopCount(2);
452  test_configurator()->AddComponentToCheck(&com2, 1);
453  component_updater()->Start();
454  message_loop.Run();
455
456  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
457  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
458  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
459  EXPECT_EQ(1, static_cast<TestInstaller*>(com2.installer)->install_count());
460
461  EXPECT_EQ(3, interceptor.GetHitCount());
462
463  ASSERT_EQ(5ul, notification_tracker().size());
464
465  TestNotificationTracker::Event ev0= notification_tracker().at(0);
466  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
467
468  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
469  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
470
471  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
472  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev2.type);
473
474  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
475  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev3.type);
476
477  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
478  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
479
480  // Also check what happens if previous check too soon.
481  test_configurator()->SetOnDemandTime(60 * 60);
482  EXPECT_EQ(ComponentUpdateService::kError,
483            component_updater()->CheckForUpdateSoon(com2));
484  // Okay, now reset to 0 for the other tests.
485  test_configurator()->SetOnDemandTime(0);
486  component_updater()->Stop();
487
488  // Test a few error cases. NOTE: We don't have callbacks for
489  // when the updates failed yet.
490  const GURL expected_update_url_3(
491      "http://localhost/upd?extra=foo"
492      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc"
493      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
494
495  // No update: error from no server response
496  interceptor.SetResponse(expected_update_url_3,
497                          test_file("updatecheck_reply_empty"));
498  notification_tracker().Reset();
499  test_configurator()->SetLoopCount(1);
500  component_updater()->Start();
501  EXPECT_EQ(ComponentUpdateService::kOk,
502            component_updater()->CheckForUpdateSoon(com2));
503
504  message_loop.Run();
505
506  ASSERT_EQ(2ul, notification_tracker().size());
507  ev0 = notification_tracker().at(0);
508  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
509  ev1 = notification_tracker().at(1);
510  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
511  component_updater()->Stop();
512
513  // No update: already updated to 1.0 so nothing new
514  interceptor.SetResponse(expected_update_url_3,
515                          test_file("updatecheck_reply_1.xml"));
516  notification_tracker().Reset();
517  test_configurator()->SetLoopCount(1);
518  component_updater()->Start();
519  EXPECT_EQ(ComponentUpdateService::kOk,
520            component_updater()->CheckForUpdateSoon(com2));
521
522  message_loop.Run();
523
524  ASSERT_EQ(2ul, notification_tracker().size());
525  ev0 = notification_tracker().at(0);
526  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
527  ev1 = notification_tracker().at(1);
528  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
529  component_updater()->Stop();
530}
531
532// Verify that a previously registered component can get re-registered
533// with a different version.
534TEST_F(ComponentUpdaterTest, CheckReRegistration) {
535  base::MessageLoop message_loop;
536  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
537  content::TestBrowserThread file_thread(BrowserThread::FILE);
538  content::TestBrowserThread io_thread(BrowserThread::IO);
539
540  io_thread.StartIOThread();
541  file_thread.Start();
542
543  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
544
545  TestInstaller installer1;
546  CrxComponent com1;
547  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1);
548  TestInstaller installer2;
549  CrxComponent com2;
550  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2);
551
552  // Start with 0.9, and update to 1.0
553  const GURL expected_update_url_1(
554      "http://localhost/upd?extra=foo"
555      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
556      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
557
558  const GURL expected_update_url_2(
559      "http://localhost/upd?extra=foo"
560      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
561      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc");
562
563  interceptor.SetResponse(expected_update_url_1,
564                          test_file("updatecheck_reply_1.xml"));
565  interceptor.SetResponse(expected_update_url_2,
566                          test_file("updatecheck_reply_1.xml"));
567  interceptor.SetResponse(GURL(expected_crx_url),
568                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
569
570  // Loop twice to issue two checks: (1) with original 0.9 version
571  // and (2) with the updated 1.0 version.
572  test_configurator()->SetLoopCount(2);
573
574  component_updater()->Start();
575  message_loop.Run();
576
577  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
578  EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
579  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
580  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
581
582  EXPECT_EQ(3, interceptor.GetHitCount());
583
584  ASSERT_EQ(5ul, notification_tracker().size());
585
586  TestNotificationTracker::Event ev0 = notification_tracker().at(0);
587  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
588
589  TestNotificationTracker::Event ev1 = notification_tracker().at(1);
590  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
591
592  TestNotificationTracker::Event ev2 = notification_tracker().at(2);
593  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
594
595  TestNotificationTracker::Event ev3 = notification_tracker().at(3);
596  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
597
598  TestNotificationTracker::Event ev4 = notification_tracker().at(4);
599  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
600
601  // Now re-register, pretending to be an even newer version (2.2)
602  TestInstaller installer3;
603  component_updater()->Stop();
604  EXPECT_EQ(ComponentUpdateService::kReplaced,
605            RegisterComponent(&com1,
606                              kTestComponent_jebg,
607                              Version("2.2"),
608                              &installer3));
609
610  // Check that we send out 2.2 as our version.
611  // Interceptor's hit count should go up by 1.
612  const GURL expected_update_url_3(
613      "http://localhost/upd?extra=foo"
614      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D2.2%26fp%3D%26uc"
615      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
616
617  interceptor.SetResponse(expected_update_url_3,
618                          test_file("updatecheck_reply_1.xml"));
619
620  notification_tracker().Reset();
621
622  // Loop once just to notice the check happening with the re-register version.
623  test_configurator()->SetLoopCount(1);
624  component_updater()->Start();
625  message_loop.Run();
626
627  ASSERT_EQ(2ul, notification_tracker().size());
628
629  ev0 = notification_tracker().at(0);
630  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
631
632  ev1 = notification_tracker().at(1);
633  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev1.type);
634
635  EXPECT_EQ(4, interceptor.GetHitCount());
636
637  // We created a new installer, so the counts go back to 0.
638  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
639  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
640  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
641  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
642
643  component_updater()->Stop();
644}
645
646// Verify that component installation falls back to downloading and installing
647// a full update if the differential update fails (in this case, because the
648// installer does not know about the existing files). We do two loops; the final
649// loop should do nothing.
650// We also check that exactly 4 network requests are issued:
651// 1- update check (loop 1)
652// 2- download differential crx
653// 3- download full crx
654// 4- update check (loop 2 - no update available)
655TEST_F(ComponentUpdaterTest, DifferentialUpdateFails) {
656  base::MessageLoop message_loop;
657  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
658  content::TestBrowserThread file_thread(BrowserThread::FILE);
659  content::TestBrowserThread io_thread(BrowserThread::IO);
660
661  io_thread.StartIOThread();
662  file_thread.Start();
663
664  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
665
666  TestInstaller installer;
667  CrxComponent com;
668  RegisterComponent(&com, kTestComponent_ihfo, Version("1.0"), &installer);
669
670  const GURL expected_update_url_1(
671      "http://localhost/upd?extra=foo"
672      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D%26uc");
673  const GURL expected_update_url_2(
674      "http://localhost/upd?extra=foo"
675      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc");
676  const GURL expected_crx_url_1(
677      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx");
678  const GURL expected_crx_url_1_diff_2(
679      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx");
680  const GURL expected_crx_url_2(
681      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx");
682
683  interceptor.SetResponse(expected_update_url_1,
684                          test_file("updatecheck_diff_reply_2.xml"));
685  interceptor.SetResponse(expected_update_url_2,
686                          test_file("updatecheck_diff_reply_3.xml"));
687  interceptor.SetResponse(expected_crx_url_1,
688                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
689  interceptor.SetResponse(
690      expected_crx_url_1_diff_2,
691      test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"));
692  interceptor.SetResponse(expected_crx_url_2,
693                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
694
695  test_configurator()->SetLoopCount(2);
696
697  component_updater()->Start();
698  message_loop.Run();
699
700  // A failed differential update does not count as a failed install.
701  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
702  EXPECT_EQ(1, static_cast<TestInstaller*>(com.installer)->install_count());
703
704  EXPECT_EQ(4, interceptor.GetHitCount());
705
706  component_updater()->Stop();
707}
708
709// Verify that we successfully propagate a patcher error.
710// ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx contains an incorrect
711// patching instruction that should fail.
712TEST_F(ComponentUpdaterTest, DifferentialUpdateFailErrorcode) {
713  base::MessageLoop message_loop;
714  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
715  content::TestBrowserThread file_thread(BrowserThread::FILE);
716  content::TestBrowserThread io_thread(BrowserThread::IO);
717
718  io_thread.StartIOThread();
719  file_thread.Start();
720
721  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
722
723  VersionedTestInstaller installer;
724  CrxComponent com;
725  RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), &installer);
726
727  const GURL expected_update_url_0(
728      "http://localhost/upd?extra=foo"
729      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D0.0%26fp%3D%26uc");
730  const GURL expected_update_url_1(
731      "http://localhost/upd?extra=foo"
732      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D1%26uc");
733  const GURL expected_update_url_2(
734      "http://localhost/upd?extra=foo"
735      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc");
736  const GURL expected_crx_url_1(
737      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx");
738  const GURL expected_crx_url_1_diff_2(
739      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx");
740  const GURL expected_crx_url_2(
741      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx");
742
743  interceptor.SetResponse(expected_update_url_0,
744                          test_file("updatecheck_diff_reply_1.xml"));
745  interceptor.SetResponse(expected_update_url_1,
746                          test_file("updatecheck_diff_reply_2.xml"));
747  interceptor.SetResponse(expected_update_url_2,
748                          test_file("updatecheck_diff_reply_3.xml"));
749  interceptor.SetResponse(expected_crx_url_1,
750                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
751  interceptor.SetResponse(
752      expected_crx_url_1_diff_2,
753      test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx"));
754  interceptor.SetResponse(expected_crx_url_2,
755                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
756
757  test_configurator()->SetLoopCount(3);
758
759  component_updater()->Start();
760  message_loop.Run();
761
762  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
763  EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
764
765  EXPECT_EQ(6, interceptor.GetHitCount());
766
767  component_updater()->Stop();
768}
769