blob: 5d2db64811bf8ee60e8b452b24b7c5fc258ee0d0 [file] [log] [blame]
sorin9797aba2015-04-17 17:15:031// Copyright 2015 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
dchengd0fc6aa92016-04-22 18:03:125#include <memory>
dcheng51ace48a2015-12-26 22:45:176#include <utility>
7
sorin9797aba2015-04-17 17:15:038#include "base/bind.h"
9#include "base/bind_helpers.h"
10#include "base/files/file_path.h"
11#include "base/files/file_util.h"
12#include "base/location.h"
avi5dd91f82015-12-25 22:30:4613#include "base/macros.h"
dchengd0fc6aa92016-04-22 18:03:1214#include "base/memory/ptr_util.h"
sorin9797aba2015-04-17 17:15:0315#include "base/memory/ref_counted.h"
sorin9797aba2015-04-17 17:15:0316#include "base/message_loop/message_loop.h"
17#include "base/path_service.h"
18#include "base/run_loop.h"
sorin85e68032015-05-27 19:50:5119#include "base/test/sequenced_worker_pool_owner.h"
gab7966d312016-05-11 20:35:0120#include "base/threading/thread_task_runner_handle.h"
sorin9797aba2015-04-17 17:15:0321#include "base/values.h"
22#include "base/version.h"
wafflesd2d9a332016-04-09 01:59:5723#include "components/prefs/testing_pref_service.h"
sorin9797aba2015-04-17 17:15:0324#include "components/update_client/crx_update_item.h"
wafflesd2d9a332016-04-09 01:59:5725#include "components/update_client/persisted_data.h"
sorin9797aba2015-04-17 17:15:0326#include "components/update_client/ping_manager.h"
sorinb120440b2015-04-27 16:34:1527#include "components/update_client/test_configurator.h"
28#include "components/update_client/test_installer.h"
sorin9797aba2015-04-17 17:15:0329#include "components/update_client/update_checker.h"
30#include "components/update_client/update_client_internal.h"
sorin9797aba2015-04-17 17:15:0331#include "testing/gmock/include/gmock/gmock.h"
32#include "testing/gtest/include/gtest/gtest.h"
33#include "url/gurl.h"
34
35namespace update_client {
36
37namespace {
38
39using base::FilePath;
40
41// Makes a copy of the file specified by |from_path| in a temporary directory
42// and returns the path of the copy. Returns true if successful. Cleans up if
43// there was an error creating the copy.
44bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
45 FilePath temp_dir;
46 bool result =
47 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir);
48 if (!result)
49 return false;
50
51 FilePath temp_file;
52 result = CreateTemporaryFileInDir(temp_dir, &temp_file);
53 if (!result)
54 return false;
55
56 result = CopyFile(from_path, temp_file);
57 if (!result) {
58 DeleteFile(temp_file, false);
59 return false;
60 }
61
62 *to_path = temp_file;
63 return true;
64}
65
66using Events = UpdateClient::Observer::Events;
67
68class MockObserver : public UpdateClient::Observer {
69 public:
70 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
71};
72
sorin7c717622015-05-26 19:59:0973class OnDemandTester {
74 public:
75 OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
76 bool expected_value);
77
78 void CheckOnDemand(Events event, const std::string&);
79
80 private:
81 const scoped_refptr<UpdateClient> update_client_;
82 const bool expected_value_;
83};
84
85OnDemandTester::OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
86 bool expected_value)
87 : update_client_(update_client), expected_value_(expected_value) {
88}
89
90void OnDemandTester::CheckOnDemand(Events event, const std::string& id) {
91 if (event == Events::COMPONENT_CHECKING_FOR_UPDATES) {
92 CrxUpdateItem update_item;
93 EXPECT_TRUE(update_client_->GetCrxUpdateState(id, &update_item));
94 EXPECT_EQ(update_item.on_demand, expected_value_);
95 }
96}
97
sorin9797aba2015-04-17 17:15:0398class FakePingManagerImpl : public PingManager {
99 public:
sorin958b5d32016-01-09 02:00:20100 explicit FakePingManagerImpl(const scoped_refptr<Configurator>& config);
sorin9797aba2015-04-17 17:15:03101 ~FakePingManagerImpl() override;
102
sorinfccbf2d2016-04-04 20:34:34103 bool SendPing(const CrxUpdateItem* item) override;
sorin9797aba2015-04-17 17:15:03104
105 const std::vector<CrxUpdateItem>& items() const;
106
107 private:
108 std::vector<CrxUpdateItem> items_;
109 DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl);
110};
111
sorin958b5d32016-01-09 02:00:20112FakePingManagerImpl::FakePingManagerImpl(
113 const scoped_refptr<Configurator>& config)
114 : PingManager(config) {}
sorin9797aba2015-04-17 17:15:03115
116FakePingManagerImpl::~FakePingManagerImpl() {
117}
118
sorinfccbf2d2016-04-04 20:34:34119bool FakePingManagerImpl::SendPing(const CrxUpdateItem* item) {
sorin9797aba2015-04-17 17:15:03120 items_.push_back(*item);
sorinfccbf2d2016-04-04 20:34:34121 return true;
sorin9797aba2015-04-17 17:15:03122}
123
124const std::vector<CrxUpdateItem>& FakePingManagerImpl::items() const {
125 return items_;
126}
127
128} // namespace
129
130using ::testing::_;
131using ::testing::AnyNumber;
132using ::testing::DoAll;
133using ::testing::InSequence;
134using ::testing::Invoke;
135using ::testing::Mock;
136using ::testing::Return;
137
sorin9797aba2015-04-17 17:15:03138using std::string;
139
140class UpdateClientTest : public testing::Test {
141 public:
142 UpdateClientTest();
143 ~UpdateClientTest() override;
144
sorin9797aba2015-04-17 17:15:03145 protected:
146 void RunThreads();
147
148 // Returns the full path to a test file.
149 static base::FilePath TestFilePath(const char* file);
150
sorine84ff702016-08-04 01:22:02151 scoped_refptr<update_client::TestConfigurator> config() { return config_; }
wafflese7dff732016-04-15 23:51:49152 update_client::PersistedData* metadata() { return metadata_.get(); }
sorin9797aba2015-04-17 17:15:03153
sorinf9f4834d2015-04-28 17:15:02154 base::Closure quit_closure() { return quit_closure_; }
155
156 private:
157 static const int kNumWorkerThreads_ = 2;
158
159 base::MessageLoopForUI message_loop_;
sorin9797aba2015-04-17 17:15:03160 base::RunLoop runloop_;
161 base::Closure quit_closure_;
162
dchengd0fc6aa92016-04-22 18:03:12163 std::unique_ptr<base::SequencedWorkerPoolOwner> worker_pool_;
sorin9797aba2015-04-17 17:15:03164
sorine84ff702016-08-04 01:22:02165 scoped_refptr<update_client::TestConfigurator> config_;
wafflesd2d9a332016-04-09 01:59:57166 std::unique_ptr<TestingPrefServiceSimple> pref_;
167 std::unique_ptr<update_client::PersistedData> metadata_;
sorinf9f4834d2015-04-28 17:15:02168
sorin9797aba2015-04-17 17:15:03169 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
170};
171
172UpdateClientTest::UpdateClientTest()
sorin85e68032015-05-27 19:50:51173 : worker_pool_(
174 new base::SequencedWorkerPoolOwner(kNumWorkerThreads_, "test")) {
sorinf9f4834d2015-04-28 17:15:02175 quit_closure_ = runloop_.QuitClosure();
176
sorin85e68032015-05-27 19:50:51177 auto pool = worker_pool_->pool();
sorinf9f4834d2015-04-28 17:15:02178 config_ = new TestConfigurator(
sorin85e68032015-05-27 19:50:51179 pool->GetSequencedTaskRunner(pool->GetSequenceToken()),
sorin7c717622015-05-26 19:59:09180 message_loop_.task_runner());
wafflesd2d9a332016-04-09 01:59:57181 pref_.reset(new TestingPrefServiceSimple());
182 PersistedData::RegisterPrefs(pref_->registry());
183 metadata_.reset(new PersistedData(pref_.get()));
sorin9797aba2015-04-17 17:15:03184}
185
186UpdateClientTest::~UpdateClientTest() {
sorin9797aba2015-04-17 17:15:03187}
188
189void UpdateClientTest::RunThreads() {
190 runloop_.Run();
191}
192
193base::FilePath UpdateClientTest::TestFilePath(const char* file) {
194 base::FilePath path;
195 PathService::Get(base::DIR_SOURCE_ROOT, &path);
196 return path.AppendASCII("components")
197 .AppendASCII("test")
198 .AppendASCII("data")
199 .AppendASCII("update_client")
200 .AppendASCII(file);
201}
202
203// Tests the scenario where one update check is done for one CRX. The CRX
204// has no update.
205TEST_F(UpdateClientTest, OneCrxNoUpdate) {
206 class DataCallbackFake {
207 public:
208 static void Callback(const std::vector<std::string>& ids,
209 std::vector<CrxComponent>* components) {
210 CrxComponent crx;
211 crx.name = "test_jebg";
212 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12213 crx.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03214 crx.installer = new TestInstaller;
215 components->push_back(crx);
216 }
217 };
218
219 class CompletionCallbackFake {
220 public:
221 static void Callback(const base::Closure& quit_closure, int error) {
222 EXPECT_EQ(0, error);
223 quit_closure.Run();
224 }
225 };
226
227 class FakeUpdateChecker : public UpdateChecker {
228 public:
dchengd0fc6aa92016-04-22 18:03:12229 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57230 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49231 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12232 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03233 }
234
235 bool CheckForUpdates(
236 const std::vector<CrxUpdateItem*>& items_to_check,
237 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36238 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03239 const UpdateCheckCallback& update_check_callback) override {
sorin590921d2016-08-11 23:48:36240 EXPECT_TRUE(enabled_component_updates);
sorin9797aba2015-04-17 17:15:03241 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:17242 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:34243 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin9797aba2015-04-17 17:15:03244 return true;
245 }
246 };
247
248 class FakeCrxDownloader : public CrxDownloader {
249 public:
dchengd0fc6aa92016-04-22 18:03:12250 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03251 bool is_background_download,
252 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10253 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12254 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03255 }
256
257 private:
sorin74e70672016-02-03 03:13:10258 FakeCrxDownloader()
259 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03260 ~FakeCrxDownloader() override {}
261
262 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
263 };
264
265 class FakePingManager : public FakePingManagerImpl {
266 public:
sorin958b5d32016-01-09 02:00:20267 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03268 : FakePingManagerImpl(config) {}
269 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
270 };
271
dchengd0fc6aa92016-04-22 18:03:12272 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09273 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17274 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03275 &FakeCrxDownloader::Create));
276
sorin7c717622015-05-26 19:59:09277 // Verify that calling Update does not set ondemand.
278 OnDemandTester ondemand_tester(update_client, false);
279
sorin9797aba2015-04-17 17:15:03280 MockObserver observer;
sorin7c717622015-05-26 19:59:09281 ON_CALL(observer, OnEvent(_, _))
282 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
283
sorin9797aba2015-04-17 17:15:03284 InSequence seq;
285 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
286 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
287 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
288 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
289
290 update_client->AddObserver(&observer);
291
292 std::vector<std::string> ids;
293 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
294
295 update_client->Update(
296 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02297 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03298
299 RunThreads();
300
301 update_client->RemoveObserver(&observer);
302}
303
304// Tests the scenario where two CRXs are checked for updates. On CRX has
305// an update, the other CRX does not.
306TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
307 class DataCallbackFake {
308 public:
309 static void Callback(const std::vector<std::string>& ids,
310 std::vector<CrxComponent>* components) {
311 CrxComponent crx1;
312 crx1.name = "test_jebg";
313 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12314 crx1.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03315 crx1.installer = new TestInstaller;
316
317 CrxComponent crx2;
318 crx2.name = "test_abag";
319 crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
pwnalldb0b72412016-08-19 21:39:12320 crx2.version = base::Version("2.2");
sorin9797aba2015-04-17 17:15:03321 crx2.installer = new TestInstaller;
322
323 components->push_back(crx1);
324 components->push_back(crx2);
325 }
326 };
327
328 class CompletionCallbackFake {
329 public:
330 static void Callback(const base::Closure& quit_closure, int error) {
331 EXPECT_EQ(0, error);
332 quit_closure.Run();
333 }
334 };
335
336 class FakeUpdateChecker : public UpdateChecker {
337 public:
dchengd0fc6aa92016-04-22 18:03:12338 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57339 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49340 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12341 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03342 }
343
344 bool CheckForUpdates(
345 const std::vector<CrxUpdateItem*>& items_to_check,
346 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36347 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03348 const UpdateCheckCallback& update_check_callback) override {
349 /*
350 Fake the following response:
351
352 <?xml version='1.0' encoding='UTF-8'?>
353 <response protocol='3.0'>
354 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
355 <updatecheck status='ok'>
356 <urls>
357 <url codebase='http://localhost/download/'/>
358 </urls>
359 <manifest version='1.0' prodversionmin='11.0.1.0'>
360 <packages>
sorin74e70672016-02-03 03:13:10361 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
362 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
363 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03364 </packages>
365 </manifest>
366 </updatecheck>
367 </app>
368 </response>
369 */
370 UpdateResponse::Result::Manifest::Package package;
371 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10372 package.hash_sha256 =
373 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03374
375 UpdateResponse::Result result;
376 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
377 result.crx_urls.push_back(GURL("http://localhost/download/"));
378 result.manifest.version = "1.0";
379 result.manifest.browser_min_version = "11.0.1.0";
380 result.manifest.packages.push_back(package);
381
382 UpdateResponse::Results results;
383 results.list.push_back(result);
384
385 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34386 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:03387 return true;
388 }
389 };
390
391 class FakeCrxDownloader : public CrxDownloader {
392 public:
dchengd0fc6aa92016-04-22 18:03:12393 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03394 bool is_background_download,
395 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10396 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12397 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03398 }
399
400 private:
sorin74e70672016-02-03 03:13:10401 FakeCrxDownloader()
402 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03403 ~FakeCrxDownloader() override {}
404
405 void DoStartDownload(const GURL& url) override {
406 DownloadMetrics download_metrics;
407 download_metrics.url = url;
408 download_metrics.downloader = DownloadMetrics::kNone;
409 download_metrics.error = 0;
410 download_metrics.downloaded_bytes = 1843;
411 download_metrics.total_bytes = 1843;
412 download_metrics.download_time_ms = 1000;
413
414 FilePath path;
415 EXPECT_TRUE(MakeTestFile(
416 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
417
418 Result result;
419 result.error = 0;
420 result.response = path;
421 result.downloaded_bytes = 1843;
422 result.total_bytes = 1843;
423
424 base::ThreadTaskRunnerHandle::Get()->PostTask(
425 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
426 base::Unretained(this), result));
427
428 base::ThreadTaskRunnerHandle::Get()->PostTask(
429 FROM_HERE,
430 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
431 base::Unretained(this), true, result, download_metrics));
432 }
433 };
434
435 class FakePingManager : public FakePingManagerImpl {
436 public:
sorin958b5d32016-01-09 02:00:20437 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03438 : FakePingManagerImpl(config) {}
439 ~FakePingManager() override {
440 const auto& ping_items = items();
441 EXPECT_EQ(1U, ping_items.size());
442 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00443 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
444 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:03445 EXPECT_EQ(0, ping_items[0].error_category);
446 EXPECT_EQ(0, ping_items[0].error_code);
447 }
448 };
449
dchengd0fc6aa92016-04-22 18:03:12450 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09451 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17452 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03453 &FakeCrxDownloader::Create));
454
455 MockObserver observer;
456 {
457 InSequence seq;
458 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
459 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
460 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
461 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
462 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
463 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
464 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
465 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
466 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
467 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
468 }
469 {
470 InSequence seq;
471 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
472 "abagagagagagagagagagagagagagagag")).Times(1);
473 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
474 "abagagagagagagagagagagagagagagag")).Times(1);
475 }
476
477 update_client->AddObserver(&observer);
478
479 std::vector<std::string> ids;
480 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
481 ids.push_back(std::string("abagagagagagagagagagagagagagagag"));
482
483 update_client->Update(
484 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02485 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03486
487 RunThreads();
488
489 update_client->RemoveObserver(&observer);
490}
491
492// Tests the update check for two CRXs scenario. Both CRXs have updates.
493TEST_F(UpdateClientTest, TwoCrxUpdate) {
494 class DataCallbackFake {
495 public:
496 static void Callback(const std::vector<std::string>& ids,
497 std::vector<CrxComponent>* components) {
498 CrxComponent crx1;
499 crx1.name = "test_jebg";
500 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12501 crx1.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03502 crx1.installer = new TestInstaller;
503
504 CrxComponent crx2;
505 crx2.name = "test_ihfo";
506 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:12507 crx2.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:03508 crx2.installer = new TestInstaller;
509
510 components->push_back(crx1);
511 components->push_back(crx2);
512 }
513 };
514
515 class CompletionCallbackFake {
516 public:
517 static void Callback(const base::Closure& quit_closure, int error) {
518 EXPECT_EQ(0, error);
519 quit_closure.Run();
520 }
521 };
522
523 class FakeUpdateChecker : public UpdateChecker {
524 public:
dchengd0fc6aa92016-04-22 18:03:12525 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57526 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49527 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12528 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03529 }
530
531 bool CheckForUpdates(
532 const std::vector<CrxUpdateItem*>& items_to_check,
533 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36534 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03535 const UpdateCheckCallback& update_check_callback) override {
536 /*
537 Fake the following response:
538
539 <?xml version='1.0' encoding='UTF-8'?>
540 <response protocol='3.0'>
541 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
542 <updatecheck status='ok'>
543 <urls>
544 <url codebase='http://localhost/download/'/>
545 </urls>
546 <manifest version='1.0' prodversionmin='11.0.1.0'>
547 <packages>
sorin74e70672016-02-03 03:13:10548 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
549 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
550 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03551 </packages>
552 </manifest>
553 </updatecheck>
554 </app>
555 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
556 <updatecheck status='ok'>
557 <urls>
558 <url codebase='http://localhost/download/'/>
559 </urls>
560 <manifest version='1.0' prodversionmin='11.0.1.0'>
561 <packages>
sorin74e70672016-02-03 03:13:10562 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
563 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
564 309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:03565 </packages>
566 </manifest>
567 </updatecheck>
568 </app>
569 </response>
570 */
571 UpdateResponse::Result::Manifest::Package package1;
572 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10573 package1.hash_sha256 =
574 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03575
576 UpdateResponse::Result result1;
577 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
578 result1.crx_urls.push_back(GURL("http://localhost/download/"));
579 result1.manifest.version = "1.0";
580 result1.manifest.browser_min_version = "11.0.1.0";
581 result1.manifest.packages.push_back(package1);
582
583 UpdateResponse::Result::Manifest::Package package2;
584 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:10585 package2.hash_sha256 =
586 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:03587
588 UpdateResponse::Result result2;
589 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
590 result2.crx_urls.push_back(GURL("http://localhost/download/"));
591 result2.manifest.version = "1.0";
592 result2.manifest.browser_min_version = "11.0.1.0";
593 result2.manifest.packages.push_back(package2);
594
595 UpdateResponse::Results results;
596 results.list.push_back(result1);
597 results.list.push_back(result2);
598
599 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34600 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:03601 return true;
602 }
603 };
604
605 class FakeCrxDownloader : public CrxDownloader {
606 public:
dchengd0fc6aa92016-04-22 18:03:12607 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03608 bool is_background_download,
609 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10610 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12611 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03612 }
613
614 private:
sorin74e70672016-02-03 03:13:10615 FakeCrxDownloader()
616 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03617 ~FakeCrxDownloader() override {}
618
619 void DoStartDownload(const GURL& url) override {
620 DownloadMetrics download_metrics;
621 FilePath path;
622 Result result;
623 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
624 download_metrics.url = url;
625 download_metrics.downloader = DownloadMetrics::kNone;
626 download_metrics.error = 0;
627 download_metrics.downloaded_bytes = 1843;
628 download_metrics.total_bytes = 1843;
629 download_metrics.download_time_ms = 1000;
630
631 EXPECT_TRUE(MakeTestFile(
632 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
633
634 result.error = 0;
635 result.response = path;
636 result.downloaded_bytes = 1843;
637 result.total_bytes = 1843;
638 } else if (url.path() ==
639 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
640 download_metrics.url = url;
641 download_metrics.downloader = DownloadMetrics::kNone;
642 download_metrics.error = 0;
643 download_metrics.downloaded_bytes = 53638;
644 download_metrics.total_bytes = 53638;
645 download_metrics.download_time_ms = 2000;
646
647 EXPECT_TRUE(MakeTestFile(
648 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
649
650 result.error = 0;
651 result.response = path;
652 result.downloaded_bytes = 53638;
653 result.total_bytes = 53638;
654 } else {
655 NOTREACHED();
656 }
657
658 base::ThreadTaskRunnerHandle::Get()->PostTask(
659 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
660 base::Unretained(this), result));
661
662 base::ThreadTaskRunnerHandle::Get()->PostTask(
663 FROM_HERE,
664 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
665 base::Unretained(this), true, result, download_metrics));
666 }
667 };
668
669 class FakePingManager : public FakePingManagerImpl {
670 public:
sorin958b5d32016-01-09 02:00:20671 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03672 : FakePingManagerImpl(config) {}
673 ~FakePingManager() override {
674 const auto& ping_items = items();
675 EXPECT_EQ(2U, ping_items.size());
676 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00677 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
678 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:03679 EXPECT_EQ(0, ping_items[0].error_category);
680 EXPECT_EQ(0, ping_items[0].error_code);
681 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:00682 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
683 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:03684 EXPECT_EQ(0, ping_items[1].error_category);
685 EXPECT_EQ(0, ping_items[1].error_code);
686 }
687 };
688
dchengd0fc6aa92016-04-22 18:03:12689 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09690 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17691 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03692 &FakeCrxDownloader::Create));
693
694 MockObserver observer;
695 {
696 InSequence seq;
697 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
698 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
699 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
700 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
701 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
702 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
703 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
704 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
705 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
706 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
707 }
708 {
709 InSequence seq;
710 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
711 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
712 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
713 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
715 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
716 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
717 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
718 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
719 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
720 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
721 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
722 }
723
724 update_client->AddObserver(&observer);
725
726 std::vector<std::string> ids;
727 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
728 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
729
730 update_client->Update(
731 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02732 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03733
734 RunThreads();
735
736 update_client->RemoveObserver(&observer);
737}
738
sorin6bb8de42015-06-03 00:23:27739// Tests the scenario where there is a download timeout for the first
740// CRX. The update for the first CRX fails. The update client waits before
741// attempting the update for the second CRX. This update succeeds.
742TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
743 class DataCallbackFake {
744 public:
745 static void Callback(const std::vector<std::string>& ids,
746 std::vector<CrxComponent>* components) {
747 CrxComponent crx1;
748 crx1.name = "test_jebg";
749 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12750 crx1.version = base::Version("0.9");
sorin6bb8de42015-06-03 00:23:27751 crx1.installer = new TestInstaller;
752
753 CrxComponent crx2;
754 crx2.name = "test_ihfo";
755 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:12756 crx2.version = base::Version("0.8");
sorin6bb8de42015-06-03 00:23:27757 crx2.installer = new TestInstaller;
758
759 components->push_back(crx1);
760 components->push_back(crx2);
761 }
762 };
763
764 class CompletionCallbackFake {
765 public:
766 static void Callback(const base::Closure& quit_closure, int error) {
767 EXPECT_EQ(0, error);
768 quit_closure.Run();
769 }
770 };
771
772 class FakeUpdateChecker : public UpdateChecker {
773 public:
dchengd0fc6aa92016-04-22 18:03:12774 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57775 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49776 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12777 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin6bb8de42015-06-03 00:23:27778 }
779
780 bool CheckForUpdates(
781 const std::vector<CrxUpdateItem*>& items_to_check,
782 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36783 bool enabled_component_updates,
sorin6bb8de42015-06-03 00:23:27784 const UpdateCheckCallback& update_check_callback) override {
785 /*
786 Fake the following response:
787
788 <?xml version='1.0' encoding='UTF-8'?>
789 <response protocol='3.0'>
790 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
791 <updatecheck status='ok'>
792 <urls>
793 <url codebase='http://localhost/download/'/>
794 </urls>
795 <manifest version='1.0' prodversionmin='11.0.1.0'>
796 <packages>
sorin74e70672016-02-03 03:13:10797 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
798 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
799 7c9b12cb7cc067667bde87'/>
sorin6bb8de42015-06-03 00:23:27800 </packages>
801 </manifest>
802 </updatecheck>
803 </app>
804 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
805 <updatecheck status='ok'>
806 <urls>
807 <url codebase='http://localhost/download/'/>
808 </urls>
809 <manifest version='1.0' prodversionmin='11.0.1.0'>
810 <packages>
sorin74e70672016-02-03 03:13:10811 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
812 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
813 309f156ea6d27229c0b3f9'/>
sorin6bb8de42015-06-03 00:23:27814 </packages>
815 </manifest>
816 </updatecheck>
817 </app>
818 </response>
819 */
820 UpdateResponse::Result::Manifest::Package package1;
821 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10822 package1.hash_sha256 =
823 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin6bb8de42015-06-03 00:23:27824
825 UpdateResponse::Result result1;
826 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
827 result1.crx_urls.push_back(GURL("http://localhost/download/"));
828 result1.manifest.version = "1.0";
829 result1.manifest.browser_min_version = "11.0.1.0";
830 result1.manifest.packages.push_back(package1);
831
832 UpdateResponse::Result::Manifest::Package package2;
833 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:10834 package2.hash_sha256 =
835 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin6bb8de42015-06-03 00:23:27836
837 UpdateResponse::Result result2;
838 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
839 result2.crx_urls.push_back(GURL("http://localhost/download/"));
840 result2.manifest.version = "1.0";
841 result2.manifest.browser_min_version = "11.0.1.0";
842 result2.manifest.packages.push_back(package2);
843
844 UpdateResponse::Results results;
845 results.list.push_back(result1);
846 results.list.push_back(result2);
847
848 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34849 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin6bb8de42015-06-03 00:23:27850 return true;
851 }
852 };
853
854 class FakeCrxDownloader : public CrxDownloader {
855 public:
dchengd0fc6aa92016-04-22 18:03:12856 static std::unique_ptr<CrxDownloader> Create(
sorin6bb8de42015-06-03 00:23:27857 bool is_background_download,
858 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10859 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12860 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin6bb8de42015-06-03 00:23:27861 }
862
863 private:
sorin74e70672016-02-03 03:13:10864 FakeCrxDownloader()
865 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin6bb8de42015-06-03 00:23:27866 ~FakeCrxDownloader() override {}
867
868 void DoStartDownload(const GURL& url) override {
869 DownloadMetrics download_metrics;
870 FilePath path;
871 Result result;
872 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
873 download_metrics.url = url;
874 download_metrics.downloader = DownloadMetrics::kNone;
875 download_metrics.error = -118;
876 download_metrics.downloaded_bytes = 0;
877 download_metrics.total_bytes = 0;
878 download_metrics.download_time_ms = 1000;
879
880 EXPECT_TRUE(MakeTestFile(
881 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
882
883 result.error = -118;
884 result.response = path;
885 result.downloaded_bytes = 0;
886 result.total_bytes = 0;
887 } else if (url.path() ==
888 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
889 download_metrics.url = url;
890 download_metrics.downloader = DownloadMetrics::kNone;
891 download_metrics.error = 0;
892 download_metrics.downloaded_bytes = 53638;
893 download_metrics.total_bytes = 53638;
894 download_metrics.download_time_ms = 2000;
895
896 EXPECT_TRUE(MakeTestFile(
897 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
898
899 result.error = 0;
900 result.response = path;
901 result.downloaded_bytes = 53638;
902 result.total_bytes = 53638;
903 } else {
904 NOTREACHED();
905 }
906
907 base::ThreadTaskRunnerHandle::Get()->PostTask(
908 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
909 base::Unretained(this), result));
910
911 base::ThreadTaskRunnerHandle::Get()->PostTask(
912 FROM_HERE,
913 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
914 base::Unretained(this), true, result, download_metrics));
915 }
916 };
917
918 class FakePingManager : public FakePingManagerImpl {
919 public:
sorin958b5d32016-01-09 02:00:20920 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin6bb8de42015-06-03 00:23:27921 : FakePingManagerImpl(config) {}
922 ~FakePingManager() override {
923 const auto& ping_items = items();
924 EXPECT_EQ(2U, ping_items.size());
925 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00926 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
927 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin6bb8de42015-06-03 00:23:27928 EXPECT_EQ(1, ping_items[0].error_category); // Network error.
929 EXPECT_EQ(-118, ping_items[0].error_code);
930 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:00931 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
932 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
sorin6bb8de42015-06-03 00:23:27933 EXPECT_EQ(0, ping_items[1].error_category);
934 EXPECT_EQ(0, ping_items[1].error_code);
935 }
936 };
937
dchengd0fc6aa92016-04-22 18:03:12938 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin6bb8de42015-06-03 00:23:27939 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17940 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin6bb8de42015-06-03 00:23:27941 &FakeCrxDownloader::Create));
942
943 MockObserver observer;
944 {
945 InSequence seq;
946 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
947 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
948 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
949 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
950 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
951 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
952 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
953 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
954 }
955 {
956 InSequence seq;
957 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
958 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
959 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
960 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
961 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
962 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
963 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
964 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
965 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
966 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
967 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
968 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
969 }
970
971 update_client->AddObserver(&observer);
972
973 std::vector<std::string> ids;
974 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
975 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
976
977 update_client->Update(
978 ids, base::Bind(&DataCallbackFake::Callback),
979 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
980
981 RunThreads();
982
983 update_client->RemoveObserver(&observer);
sorin6bb8de42015-06-03 00:23:27984}
985
sorin9797aba2015-04-17 17:15:03986// Tests the differential update scenario for one CRX.
987TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
988 class DataCallbackFake {
989 public:
990 static void Callback(const std::vector<std::string>& ids,
991 std::vector<CrxComponent>* components) {
992 static int num_calls = 0;
993
994 // Must use the same stateful installer object.
995 static scoped_refptr<CrxInstaller> installer(
996 new VersionedTestInstaller());
997
998 ++num_calls;
999
1000 CrxComponent crx;
1001 crx.name = "test_ihfo";
1002 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
1003 crx.installer = installer;
1004 if (num_calls == 1) {
pwnalldb0b72412016-08-19 21:39:121005 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031006 } else if (num_calls == 2) {
pwnalldb0b72412016-08-19 21:39:121007 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031008 } else {
1009 NOTREACHED();
1010 }
1011
1012 components->push_back(crx);
1013 }
1014 };
1015
1016 class CompletionCallbackFake {
1017 public:
1018 static void Callback(const base::Closure& quit_closure, int error) {
1019 EXPECT_EQ(0, error);
1020 quit_closure.Run();
1021 }
1022 };
1023
1024 class FakeUpdateChecker : public UpdateChecker {
1025 public:
dchengd0fc6aa92016-04-22 18:03:121026 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571027 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491028 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121029 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031030 }
1031
1032 bool CheckForUpdates(
1033 const std::vector<CrxUpdateItem*>& items_to_check,
1034 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361035 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031036 const UpdateCheckCallback& update_check_callback) override {
1037 static int num_call = 0;
1038 ++num_call;
1039
1040 UpdateResponse::Results results;
1041
1042 if (num_call == 1) {
1043 /*
1044 Fake the following response:
1045 <?xml version='1.0' encoding='UTF-8'?>
1046 <response protocol='3.0'>
1047 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1048 <updatecheck status='ok'>
1049 <urls>
1050 <url codebase='http://localhost/download/'/>
1051 </urls>
1052 <manifest version='1.0' prodversionmin='11.0.1.0'>
1053 <packages>
sorin74e70672016-02-03 03:13:101054 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1055 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1056 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031057 </packages>
1058 </manifest>
1059 </updatecheck>
1060 </app>
1061 </response>
1062 */
1063 UpdateResponse::Result::Manifest::Package package;
1064 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101065 package.hash_sha256 =
1066 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031067 package.fingerprint = "1";
1068 UpdateResponse::Result result;
1069 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1070 result.crx_urls.push_back(GURL("http://localhost/download/"));
1071 result.manifest.version = "1.0";
1072 result.manifest.browser_min_version = "11.0.1.0";
1073 result.manifest.packages.push_back(package);
1074 results.list.push_back(result);
1075 } else if (num_call == 2) {
1076 /*
1077 Fake the following response:
1078 <?xml version='1.0' encoding='UTF-8'?>
1079 <response protocol='3.0'>
1080 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1081 <updatecheck status='ok'>
1082 <urls>
1083 <url codebase='http://localhost/download/'/>
1084 <url codebasediff='http://localhost/download/'/>
1085 </urls>
1086 <manifest version='2.0' prodversionmin='11.0.1.0'>
1087 <packages>
1088 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1089 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101090 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1091 0ecde26c262bad942b112990'
1092 fp='22'
1093 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261094 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031095 </packages>
1096 </manifest>
1097 </updatecheck>
1098 </app>
1099 </response>
1100 */
1101 UpdateResponse::Result::Manifest::Package package;
1102 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1103 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101104 package.hash_sha256 =
1105 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1106 package.hashdiff_sha256 =
1107 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031108 package.fingerprint = "22";
1109 UpdateResponse::Result result;
1110 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1111 result.crx_urls.push_back(GURL("http://localhost/download/"));
1112 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1113 result.manifest.version = "2.0";
1114 result.manifest.browser_min_version = "11.0.1.0";
1115 result.manifest.packages.push_back(package);
1116 results.list.push_back(result);
1117 } else {
1118 NOTREACHED();
1119 }
1120
1121 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341122 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031123 return true;
1124 }
1125 };
1126
1127 class FakeCrxDownloader : public CrxDownloader {
1128 public:
dchengd0fc6aa92016-04-22 18:03:121129 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031130 bool is_background_download,
1131 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101132 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121133 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031134 }
1135
1136 private:
sorin74e70672016-02-03 03:13:101137 FakeCrxDownloader()
1138 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031139 ~FakeCrxDownloader() override {}
1140
1141 void DoStartDownload(const GURL& url) override {
1142 DownloadMetrics download_metrics;
1143 FilePath path;
1144 Result result;
1145 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1146 download_metrics.url = url;
1147 download_metrics.downloader = DownloadMetrics::kNone;
1148 download_metrics.error = 0;
1149 download_metrics.downloaded_bytes = 53638;
1150 download_metrics.total_bytes = 53638;
1151 download_metrics.download_time_ms = 2000;
1152
1153 EXPECT_TRUE(MakeTestFile(
1154 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1155
1156 result.error = 0;
1157 result.response = path;
1158 result.downloaded_bytes = 53638;
1159 result.total_bytes = 53638;
1160 } else if (url.path() ==
1161 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1162 download_metrics.url = url;
1163 download_metrics.downloader = DownloadMetrics::kNone;
1164 download_metrics.error = 0;
1165 download_metrics.downloaded_bytes = 2105;
1166 download_metrics.total_bytes = 2105;
1167 download_metrics.download_time_ms = 1000;
1168
1169 EXPECT_TRUE(MakeTestFile(
1170 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1171
1172 result.error = 0;
1173 result.response = path;
1174 result.downloaded_bytes = 2105;
1175 result.total_bytes = 2105;
1176 } else {
1177 NOTREACHED();
1178 }
1179
1180 base::ThreadTaskRunnerHandle::Get()->PostTask(
1181 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1182 base::Unretained(this), result));
1183
1184 base::ThreadTaskRunnerHandle::Get()->PostTask(
1185 FROM_HERE,
1186 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1187 base::Unretained(this), true, result, download_metrics));
1188 }
1189 };
1190
1191 class FakePingManager : public FakePingManagerImpl {
1192 public:
sorin958b5d32016-01-09 02:00:201193 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031194 : FakePingManagerImpl(config) {}
1195 ~FakePingManager() override {
1196 const auto& ping_items = items();
1197 EXPECT_EQ(2U, ping_items.size());
1198 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001199 EXPECT_EQ(base::Version("0.8"), ping_items[0].previous_version);
1200 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031201 EXPECT_EQ(0, ping_items[0].error_category);
1202 EXPECT_EQ(0, ping_items[0].error_code);
1203 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:001204 EXPECT_EQ(base::Version("1.0"), ping_items[1].previous_version);
1205 EXPECT_EQ(base::Version("2.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:031206 EXPECT_EQ(0, ping_items[1].diff_error_category);
1207 EXPECT_EQ(0, ping_items[1].diff_error_code);
1208 }
1209 };
1210
dchengd0fc6aa92016-04-22 18:03:121211 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091212 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171213 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031214 &FakeCrxDownloader::Create));
1215
1216 MockObserver observer;
1217 {
1218 InSequence seq;
1219 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1220 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1221 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1222 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1223 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1224 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1225 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1226 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1227 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1228 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1229 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1230 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1231 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1232 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1233 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1234 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1235 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1236 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1237 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1238 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1239 }
1240
1241 update_client->AddObserver(&observer);
1242
1243 std::vector<std::string> ids;
1244 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
1245
1246 {
1247 base::RunLoop runloop;
1248 update_client->Update(
1249 ids, base::Bind(&DataCallbackFake::Callback),
1250 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1251 runloop.Run();
1252 }
1253
1254 {
1255 base::RunLoop runloop;
1256 update_client->Update(
1257 ids, base::Bind(&DataCallbackFake::Callback),
1258 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1259 runloop.Run();
1260 }
1261
1262 update_client->RemoveObserver(&observer);
1263}
1264
1265// Tests the update scenario for one CRX where the CRX installer returns
1266// an error.
1267TEST_F(UpdateClientTest, OneCrxInstallError) {
1268 class MockInstaller : public CrxInstaller {
1269 public:
1270 MOCK_METHOD1(OnUpdateError, void(int error));
1271 MOCK_METHOD2(Install,
1272 bool(const base::DictionaryValue& manifest,
1273 const base::FilePath& unpack_path));
1274 MOCK_METHOD2(GetInstalledFile,
1275 bool(const std::string& file, base::FilePath* installed_file));
1276 MOCK_METHOD0(Uninstall, bool());
1277
1278 static void OnInstall(const base::DictionaryValue& manifest,
1279 const base::FilePath& unpack_path) {
1280 base::DeleteFile(unpack_path, true);
1281 }
1282
1283 protected:
1284 ~MockInstaller() override {}
1285 };
1286
1287 class DataCallbackFake {
1288 public:
1289 static void Callback(const std::vector<std::string>& ids,
1290 std::vector<CrxComponent>* components) {
1291 scoped_refptr<MockInstaller> installer(new MockInstaller());
1292
1293 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
1294 EXPECT_CALL(*installer, Install(_, _))
1295 .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false)));
1296 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
1297 EXPECT_CALL(*installer, Uninstall()).Times(0);
1298
1299 CrxComponent crx;
1300 crx.name = "test_jebg";
1301 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121302 crx.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:031303 crx.installer = installer;
1304 components->push_back(crx);
1305 }
1306 };
1307
1308 class CompletionCallbackFake {
1309 public:
1310 static void Callback(const base::Closure& quit_closure, int error) {
1311 EXPECT_EQ(0, error);
1312 quit_closure.Run();
1313 }
1314 };
1315
1316 class FakeUpdateChecker : public UpdateChecker {
1317 public:
dchengd0fc6aa92016-04-22 18:03:121318 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571319 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491320 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121321 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031322 }
1323
1324 bool CheckForUpdates(
1325 const std::vector<CrxUpdateItem*>& items_to_check,
1326 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361327 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031328 const UpdateCheckCallback& update_check_callback) override {
1329 /*
1330 Fake the following response:
1331
1332 <?xml version='1.0' encoding='UTF-8'?>
1333 <response protocol='3.0'>
1334 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1335 <updatecheck status='ok'>
1336 <urls>
1337 <url codebase='http://localhost/download/'/>
1338 </urls>
1339 <manifest version='1.0' prodversionmin='11.0.1.0'>
1340 <packages>
sorin74e70672016-02-03 03:13:101341 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1342 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1343 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:031344 </packages>
1345 </manifest>
1346 </updatecheck>
1347 </app>
1348 </response>
1349 */
1350 UpdateResponse::Result::Manifest::Package package;
1351 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101352 package.hash_sha256 =
1353 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:031354 UpdateResponse::Result result;
1355 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
1356 result.crx_urls.push_back(GURL("http://localhost/download/"));
1357 result.manifest.version = "1.0";
1358 result.manifest.browser_min_version = "11.0.1.0";
1359 result.manifest.packages.push_back(package);
1360
1361 UpdateResponse::Results results;
1362 results.list.push_back(result);
1363
1364 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341365 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031366 return true;
1367 }
1368 };
1369
1370 class FakeCrxDownloader : public CrxDownloader {
1371 public:
dchengd0fc6aa92016-04-22 18:03:121372 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031373 bool is_background_download,
1374 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101375 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121376 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031377 }
1378
1379 private:
sorin74e70672016-02-03 03:13:101380 FakeCrxDownloader()
1381 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031382 ~FakeCrxDownloader() override {}
1383
1384 void DoStartDownload(const GURL& url) override {
1385 DownloadMetrics download_metrics;
1386 download_metrics.url = url;
1387 download_metrics.downloader = DownloadMetrics::kNone;
1388 download_metrics.error = 0;
1389 download_metrics.downloaded_bytes = 1843;
1390 download_metrics.total_bytes = 1843;
1391 download_metrics.download_time_ms = 1000;
1392
1393 FilePath path;
1394 EXPECT_TRUE(MakeTestFile(
1395 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1396
1397 Result result;
1398 result.error = 0;
1399 result.response = path;
1400 result.downloaded_bytes = 1843;
1401 result.total_bytes = 1843;
1402
1403 base::ThreadTaskRunnerHandle::Get()->PostTask(
1404 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1405 base::Unretained(this), result));
1406
1407 base::ThreadTaskRunnerHandle::Get()->PostTask(
1408 FROM_HERE,
1409 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1410 base::Unretained(this), true, result, download_metrics));
1411 }
1412 };
1413
1414 class FakePingManager : public FakePingManagerImpl {
1415 public:
sorin958b5d32016-01-09 02:00:201416 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031417 : FakePingManagerImpl(config) {}
1418 ~FakePingManager() override {
1419 const auto& ping_items = items();
1420 EXPECT_EQ(1U, ping_items.size());
1421 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001422 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
1423 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031424 EXPECT_EQ(3, ping_items[0].error_category); // kInstallError.
1425 EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError.
1426 }
1427 };
1428
dchengd0fc6aa92016-04-22 18:03:121429 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091430 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171431 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031432 &FakeCrxDownloader::Create));
1433
1434 MockObserver observer;
1435 {
1436 InSequence seq;
1437 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1438 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1439 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1440 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1441 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1442 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1443 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1444 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1445 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1446 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1447 }
1448
1449 update_client->AddObserver(&observer);
1450
1451 std::vector<std::string> ids;
1452 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
1453
1454 update_client->Update(
1455 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:021456 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031457
1458 RunThreads();
1459
1460 update_client->RemoveObserver(&observer);
1461}
1462
1463// Tests the fallback from differential to full update scenario for one CRX.
1464TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
1465 class DataCallbackFake {
1466 public:
1467 static void Callback(const std::vector<std::string>& ids,
1468 std::vector<CrxComponent>* components) {
1469 static int num_calls = 0;
1470
1471 // Must use the same stateful installer object.
1472 static scoped_refptr<CrxInstaller> installer(
1473 new VersionedTestInstaller());
1474
1475 ++num_calls;
1476
1477 CrxComponent crx;
1478 crx.name = "test_ihfo";
1479 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
1480 crx.installer = installer;
1481 if (num_calls == 1) {
pwnalldb0b72412016-08-19 21:39:121482 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031483 } else if (num_calls == 2) {
pwnalldb0b72412016-08-19 21:39:121484 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031485 } else {
1486 NOTREACHED();
1487 }
1488
1489 components->push_back(crx);
1490 }
1491 };
1492
1493 class CompletionCallbackFake {
1494 public:
1495 static void Callback(const base::Closure& quit_closure, int error) {
1496 EXPECT_EQ(0, error);
1497 quit_closure.Run();
1498 }
1499 };
1500
1501 class FakeUpdateChecker : public UpdateChecker {
1502 public:
dchengd0fc6aa92016-04-22 18:03:121503 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571504 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491505 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121506 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031507 }
1508
1509 bool CheckForUpdates(
1510 const std::vector<CrxUpdateItem*>& items_to_check,
1511 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361512 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031513 const UpdateCheckCallback& update_check_callback) override {
1514 static int num_call = 0;
1515 ++num_call;
1516
1517 UpdateResponse::Results results;
1518
1519 if (num_call == 1) {
1520 /*
1521 Fake the following response:
1522 <?xml version='1.0' encoding='UTF-8'?>
1523 <response protocol='3.0'>
1524 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1525 <updatecheck status='ok'>
1526 <urls>
1527 <url codebase='http://localhost/download/'/>
1528 </urls>
1529 <manifest version='1.0' prodversionmin='11.0.1.0'>
1530 <packages>
sorin74e70672016-02-03 03:13:101531 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1532 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1533 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031534 </packages>
1535 </manifest>
1536 </updatecheck>
1537 </app>
1538 </response>
1539 */
1540 UpdateResponse::Result::Manifest::Package package;
1541 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101542 package.hash_sha256 =
1543 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031544 package.fingerprint = "1";
1545 UpdateResponse::Result result;
1546 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1547 result.crx_urls.push_back(GURL("http://localhost/download/"));
1548 result.manifest.version = "1.0";
1549 result.manifest.browser_min_version = "11.0.1.0";
1550 result.manifest.packages.push_back(package);
1551 results.list.push_back(result);
1552 } else if (num_call == 2) {
1553 /*
1554 Fake the following response:
1555 <?xml version='1.0' encoding='UTF-8'?>
1556 <response protocol='3.0'>
1557 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1558 <updatecheck status='ok'>
1559 <urls>
1560 <url codebase='http://localhost/download/'/>
1561 <url codebasediff='http://localhost/download/'/>
1562 </urls>
1563 <manifest version='2.0' prodversionmin='11.0.1.0'>
1564 <packages>
1565 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1566 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101567 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1568 0ecde26c262bad942b112990'
1569 fp='22'
1570 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261571 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031572 </packages>
1573 </manifest>
1574 </updatecheck>
1575 </app>
1576 </response>
1577 */
1578 UpdateResponse::Result::Manifest::Package package;
1579 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1580 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101581 package.hash_sha256 =
1582 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1583 package.hashdiff_sha256 =
1584 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031585 package.fingerprint = "22";
1586 UpdateResponse::Result result;
1587 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1588 result.crx_urls.push_back(GURL("http://localhost/download/"));
1589 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1590 result.manifest.version = "2.0";
1591 result.manifest.browser_min_version = "11.0.1.0";
1592 result.manifest.packages.push_back(package);
1593 results.list.push_back(result);
1594 } else {
1595 NOTREACHED();
1596 }
1597
1598 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341599 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031600 return true;
1601 }
1602 };
1603
1604 class FakeCrxDownloader : public CrxDownloader {
1605 public:
dchengd0fc6aa92016-04-22 18:03:121606 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031607 bool is_background_download,
1608 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101609 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121610 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031611 }
1612
1613 private:
sorin74e70672016-02-03 03:13:101614 FakeCrxDownloader()
1615 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031616 ~FakeCrxDownloader() override {}
1617
1618 void DoStartDownload(const GURL& url) override {
1619 DownloadMetrics download_metrics;
1620 FilePath path;
1621 Result result;
1622 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1623 download_metrics.url = url;
1624 download_metrics.downloader = DownloadMetrics::kNone;
1625 download_metrics.error = 0;
1626 download_metrics.downloaded_bytes = 53638;
1627 download_metrics.total_bytes = 53638;
1628 download_metrics.download_time_ms = 2000;
1629
1630 EXPECT_TRUE(MakeTestFile(
1631 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1632
1633 result.error = 0;
1634 result.response = path;
1635 result.downloaded_bytes = 53638;
1636 result.total_bytes = 53638;
1637 } else if (url.path() ==
1638 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1639 // A download error is injected on this execution path.
1640 download_metrics.url = url;
1641 download_metrics.downloader = DownloadMetrics::kNone;
1642 download_metrics.error = -1;
1643 download_metrics.downloaded_bytes = 0;
1644 download_metrics.total_bytes = 2105;
1645 download_metrics.download_time_ms = 1000;
1646
1647 EXPECT_TRUE(MakeTestFile(
1648 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1649
1650 result.error = -1;
1651 result.response = path;
1652 result.downloaded_bytes = 0;
1653 result.total_bytes = 2105;
1654 } else if (url.path() ==
1655 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
1656 download_metrics.url = url;
1657 download_metrics.downloader = DownloadMetrics::kNone;
1658 download_metrics.error = 0;
1659 download_metrics.downloaded_bytes = 53855;
1660 download_metrics.total_bytes = 53855;
1661 download_metrics.download_time_ms = 1000;
1662
1663 EXPECT_TRUE(MakeTestFile(
1664 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
1665
1666 result.error = 0;
1667 result.response = path;
1668 result.downloaded_bytes = 53855;
1669 result.total_bytes = 53855;
1670 }
1671
1672 base::ThreadTaskRunnerHandle::Get()->PostTask(
1673 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1674 base::Unretained(this), result));
1675
1676 base::ThreadTaskRunnerHandle::Get()->PostTask(
1677 FROM_HERE,
1678 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1679 base::Unretained(this), true, result, download_metrics));
1680 }
1681 };
1682
1683 class FakePingManager : public FakePingManagerImpl {
1684 public:
sorin958b5d32016-01-09 02:00:201685 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031686 : FakePingManagerImpl(config) {}
1687 ~FakePingManager() override {
1688 const auto& ping_items = items();
1689 EXPECT_EQ(2U, ping_items.size());
1690 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001691 EXPECT_EQ(base::Version("0.8"), ping_items[0].previous_version);
1692 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031693 EXPECT_EQ(0, ping_items[0].error_category);
1694 EXPECT_EQ(0, ping_items[0].error_code);
1695 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:001696 EXPECT_EQ(base::Version("1.0"), ping_items[1].previous_version);
1697 EXPECT_EQ(base::Version("2.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:031698 EXPECT_TRUE(ping_items[1].diff_update_failed);
1699 EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError.
1700 EXPECT_EQ(-1, ping_items[1].diff_error_code);
1701 }
1702 };
1703
dchengd0fc6aa92016-04-22 18:03:121704 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091705 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171706 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031707 &FakeCrxDownloader::Create));
1708
1709 MockObserver observer;
1710 {
1711 InSequence seq;
1712 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1713 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1715 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1716 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1717 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1718 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1719 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1720 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1721 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1722
1723 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1724 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1725 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1726 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1727 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1728 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1729 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1730 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1731 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1732 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1733 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1734 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1735 }
1736
1737 update_client->AddObserver(&observer);
1738
1739 std::vector<std::string> ids;
1740 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
1741
1742 {
1743 base::RunLoop runloop;
1744 update_client->Update(
1745 ids, base::Bind(&DataCallbackFake::Callback),
1746 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1747 runloop.Run();
1748 }
1749
1750 {
1751 base::RunLoop runloop;
1752 update_client->Update(
1753 ids, base::Bind(&DataCallbackFake::Callback),
1754 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1755 runloop.Run();
1756 }
1757
1758 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:091759}
1760
1761// Tests the queuing of update checks. In this scenario, two update checks are
1762// done for one CRX. The second update check call is queued up and will run
1763// after the first check has completed. The CRX has no updates.
1764TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
1765 class DataCallbackFake {
1766 public:
1767 static void Callback(const std::vector<std::string>& ids,
1768 std::vector<CrxComponent>* components) {
1769 CrxComponent crx;
1770 crx.name = "test_jebg";
1771 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121772 crx.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:091773 crx.installer = new TestInstaller;
1774 components->push_back(crx);
1775 }
1776 };
1777
1778 class CompletionCallbackFake {
1779 public:
1780 static void Callback(const base::Closure& quit_closure, int error) {
1781 static int num_call = 0;
1782 ++num_call;
1783
1784 EXPECT_EQ(0, error);
1785
1786 if (num_call == 2)
1787 quit_closure.Run();
1788 }
1789 };
1790
1791 class FakeUpdateChecker : public UpdateChecker {
1792 public:
dchengd0fc6aa92016-04-22 18:03:121793 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571794 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491795 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121796 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin7c717622015-05-26 19:59:091797 }
1798
1799 bool CheckForUpdates(
1800 const std::vector<CrxUpdateItem*>& items_to_check,
1801 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361802 bool enabled_component_updates,
sorin7c717622015-05-26 19:59:091803 const UpdateCheckCallback& update_check_callback) override {
1804 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:171805 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:341806 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin7c717622015-05-26 19:59:091807 return true;
1808 }
1809 };
1810
1811 class FakeCrxDownloader : public CrxDownloader {
1812 public:
dchengd0fc6aa92016-04-22 18:03:121813 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:091814 bool is_background_download,
1815 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101816 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121817 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin7c717622015-05-26 19:59:091818 }
1819
1820 private:
sorin74e70672016-02-03 03:13:101821 FakeCrxDownloader()
1822 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin7c717622015-05-26 19:59:091823 ~FakeCrxDownloader() override {}
1824
1825 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
1826 };
1827
1828 class FakePingManager : public FakePingManagerImpl {
1829 public:
sorin958b5d32016-01-09 02:00:201830 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin7c717622015-05-26 19:59:091831 : FakePingManagerImpl(config) {}
1832 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
1833 };
1834
dchengd0fc6aa92016-04-22 18:03:121835 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091836 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171837 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin7c717622015-05-26 19:59:091838 &FakeCrxDownloader::Create));
1839
1840 MockObserver observer;
1841 InSequence seq;
1842 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1843 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1844 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1845 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1846 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1847 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1848 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1849 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1850
1851 update_client->AddObserver(&observer);
1852
1853 std::vector<std::string> ids;
1854 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
1855
1856 update_client->Update(
1857 ids, base::Bind(&DataCallbackFake::Callback),
1858 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
1859 update_client->Update(
1860 ids, base::Bind(&DataCallbackFake::Callback),
1861 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
1862
1863 RunThreads();
1864
1865 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:091866}
1867
1868// Tests the install of one CRX.
1869TEST_F(UpdateClientTest, OneCrxInstall) {
1870 class DataCallbackFake {
1871 public:
1872 static void Callback(const std::vector<std::string>& ids,
1873 std::vector<CrxComponent>* components) {
1874 CrxComponent crx;
1875 crx.name = "test_jebg";
1876 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121877 crx.version = base::Version("0.0");
sorin7c717622015-05-26 19:59:091878 crx.installer = new TestInstaller;
1879
1880 components->push_back(crx);
1881 }
1882 };
1883
1884 class CompletionCallbackFake {
1885 public:
1886 static void Callback(const base::Closure& quit_closure, int error) {
1887 EXPECT_EQ(0, error);
1888 quit_closure.Run();
1889 }
1890 };
1891
1892 class FakeUpdateChecker : public UpdateChecker {
1893 public:
dchengd0fc6aa92016-04-22 18:03:121894 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571895 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491896 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121897 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin7c717622015-05-26 19:59:091898 }
1899
1900 bool CheckForUpdates(
1901 const std::vector<CrxUpdateItem*>& items_to_check,
1902 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361903 bool enabled_component_updates,
sorin7c717622015-05-26 19:59:091904 const UpdateCheckCallback& update_check_callback) override {
1905 /*
1906 Fake the following response:
1907
1908 <?xml version='1.0' encoding='UTF-8'?>
1909 <response protocol='3.0'>
1910 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1911 <updatecheck status='ok'>
1912 <urls>
1913 <url codebase='http://localhost/download/'/>
1914 </urls>
1915 <manifest version='1.0' prodversionmin='11.0.1.0'>
1916 <packages>
sorin74e70672016-02-03 03:13:101917 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1918 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1919 7c9b12cb7cc067667bde87'/>
sorin7c717622015-05-26 19:59:091920 </packages>
1921 </manifest>
1922 </updatecheck>
1923 </app>
1924 </response>
1925 */
1926 UpdateResponse::Result::Manifest::Package package;
1927 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101928 package.hash_sha256 =
1929 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin7c717622015-05-26 19:59:091930 UpdateResponse::Result result;
1931 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
1932 result.crx_urls.push_back(GURL("http://localhost/download/"));
1933 result.manifest.version = "1.0";
1934 result.manifest.browser_min_version = "11.0.1.0";
1935 result.manifest.packages.push_back(package);
1936
1937 UpdateResponse::Results results;
1938 results.list.push_back(result);
1939
1940 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341941 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin7c717622015-05-26 19:59:091942 return true;
1943 }
1944 };
1945
1946 class FakeCrxDownloader : public CrxDownloader {
1947 public:
dchengd0fc6aa92016-04-22 18:03:121948 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:091949 bool is_background_download,
1950 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101951 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121952 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin7c717622015-05-26 19:59:091953 }
1954
1955 private:
sorin74e70672016-02-03 03:13:101956 FakeCrxDownloader()
1957 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin7c717622015-05-26 19:59:091958 ~FakeCrxDownloader() override {}
1959
1960 void DoStartDownload(const GURL& url) override {
1961 DownloadMetrics download_metrics;
1962 FilePath path;
1963 Result result;
1964 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
1965 download_metrics.url = url;
1966 download_metrics.downloader = DownloadMetrics::kNone;
1967 download_metrics.error = 0;
1968 download_metrics.downloaded_bytes = 1843;
1969 download_metrics.total_bytes = 1843;
1970 download_metrics.download_time_ms = 1000;
1971
1972 EXPECT_TRUE(MakeTestFile(
1973 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1974
1975 result.error = 0;
1976 result.response = path;
1977 result.downloaded_bytes = 1843;
1978 result.total_bytes = 1843;
1979 } else {
1980 NOTREACHED();
1981 }
1982
1983 base::ThreadTaskRunnerHandle::Get()->PostTask(
1984 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1985 base::Unretained(this), result));
1986
1987 base::ThreadTaskRunnerHandle::Get()->PostTask(
1988 FROM_HERE,
1989 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1990 base::Unretained(this), true, result, download_metrics));
1991 }
1992 };
1993
1994 class FakePingManager : public FakePingManagerImpl {
1995 public:
sorin958b5d32016-01-09 02:00:201996 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin7c717622015-05-26 19:59:091997 : FakePingManagerImpl(config) {}
1998 ~FakePingManager() override {
1999 const auto& ping_items = items();
2000 EXPECT_EQ(1U, ping_items.size());
2001 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:002002 EXPECT_EQ(base::Version("0.0"), ping_items[0].previous_version);
2003 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin7c717622015-05-26 19:59:092004 EXPECT_EQ(0, ping_items[0].error_category);
2005 EXPECT_EQ(0, ping_items[0].error_code);
2006 }
2007 };
2008
dchengd0fc6aa92016-04-22 18:03:122009 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:092010 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:172011 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin7c717622015-05-26 19:59:092012 &FakeCrxDownloader::Create));
2013
2014 // Verify that calling Install sets ondemand.
2015 OnDemandTester ondemand_tester(update_client, true);
2016
2017 MockObserver observer;
2018 ON_CALL(observer, OnEvent(_, _))
2019 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
2020
2021 InSequence seq;
2022 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2023 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2024 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2025 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2026 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
2027 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2028 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2029 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2030 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2031 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2032
2033 update_client->AddObserver(&observer);
2034
2035 update_client->Install(
2036 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2037 base::Bind(&DataCallbackFake::Callback),
2038 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2039
2040 RunThreads();
2041
2042 update_client->RemoveObserver(&observer);
sorin9797aba2015-04-17 17:15:032043}
2044
sorin08d153c2015-10-30 00:04:202045// Tests that overlapping installs of the same CRX result in an error.
2046TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
2047 class DataCallbackFake {
2048 public:
2049 static void Callback(const std::vector<std::string>& ids,
2050 std::vector<CrxComponent>* components) {
2051 CrxComponent crx;
2052 crx.name = "test_jebg";
2053 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122054 crx.version = base::Version("0.0");
sorin08d153c2015-10-30 00:04:202055 crx.installer = new TestInstaller;
2056
2057 components->push_back(crx);
2058 }
2059 };
2060
2061 class CompletionCallbackFake {
2062 public:
2063 static void Callback(const base::Closure& quit_closure, int error) {
2064 static int num_call = 0;
2065 ++num_call;
2066
2067 EXPECT_LE(num_call, 2);
2068
2069 if (num_call == 1) {
2070 EXPECT_EQ(Error::ERROR_UPDATE_IN_PROGRESS, error);
2071 return;
2072 }
2073 if (num_call == 2) {
2074 EXPECT_EQ(0, error);
2075 quit_closure.Run();
2076 }
2077 }
2078 };
2079
2080 class FakeUpdateChecker : public UpdateChecker {
2081 public:
dchengd0fc6aa92016-04-22 18:03:122082 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572083 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492084 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122085 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin08d153c2015-10-30 00:04:202086 }
2087
2088 bool CheckForUpdates(
2089 const std::vector<CrxUpdateItem*>& items_to_check,
2090 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362091 bool enabled_component_updates,
sorin08d153c2015-10-30 00:04:202092 const UpdateCheckCallback& update_check_callback) override {
2093 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:172094 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:342095 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin08d153c2015-10-30 00:04:202096 return true;
2097 }
2098 };
2099
2100 class FakeCrxDownloader : public CrxDownloader {
2101 public:
dchengd0fc6aa92016-04-22 18:03:122102 static std::unique_ptr<CrxDownloader> Create(
sorin08d153c2015-10-30 00:04:202103 bool is_background_download,
2104 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102105 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122106 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin08d153c2015-10-30 00:04:202107 }
2108
2109 private:
sorin74e70672016-02-03 03:13:102110 FakeCrxDownloader()
2111 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin08d153c2015-10-30 00:04:202112 ~FakeCrxDownloader() override {}
2113
2114 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2115 };
2116
2117 class FakePingManager : public FakePingManagerImpl {
2118 public:
sorin958b5d32016-01-09 02:00:202119 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin08d153c2015-10-30 00:04:202120 : FakePingManagerImpl(config) {}
2121 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
2122 };
2123
dchengd0fc6aa92016-04-22 18:03:122124 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin08d153c2015-10-30 00:04:202125 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:172126 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin08d153c2015-10-30 00:04:202127 &FakeCrxDownloader::Create));
2128
2129 // Verify that calling Install sets ondemand.
2130 OnDemandTester ondemand_tester(update_client, true);
2131
2132 MockObserver observer;
2133 ON_CALL(observer, OnEvent(_, _))
2134 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
2135
2136 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2137 "jebgalgnebhfojomionfpkfelancnnkf"))
2138 .Times(1);
2139 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2140 "jebgalgnebhfojomionfpkfelancnnkf"))
2141 .Times(1);
2142
2143 update_client->AddObserver(&observer);
2144
2145 update_client->Install(
2146 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2147 base::Bind(&DataCallbackFake::Callback),
2148 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2149
2150 update_client->Install(
2151 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2152 base::Bind(&DataCallbackFake::Callback),
2153 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2154
2155 RunThreads();
2156
2157 update_client->RemoveObserver(&observer);
sorin08d153c2015-10-30 00:04:202158}
2159
asargente90363b2015-09-09 22:40:072160// Make sure that we don't get any crashes when trying to update an empty list
2161// of ids.
2162TEST_F(UpdateClientTest, EmptyIdList) {
2163 class DataCallbackFake {
2164 public:
2165 static void Callback(const std::vector<std::string>& ids,
2166 std::vector<CrxComponent>* components) {}
2167 };
2168
2169 class CompletionCallbackFake {
2170 public:
2171 static void Callback(const base::Closure& quit_closure, int error) {
2172 quit_closure.Run();
2173 }
2174 };
2175 class FakeUpdateChecker : public UpdateChecker {
2176 public:
dchengd0fc6aa92016-04-22 18:03:122177 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572178 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492179 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122180 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
asargente90363b2015-09-09 22:40:072181 }
2182
2183 bool CheckForUpdates(
2184 const std::vector<CrxUpdateItem*>& items_to_check,
2185 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362186 bool enabled_component_updates,
asargente90363b2015-09-09 22:40:072187 const UpdateCheckCallback& update_check_callback) override {
2188 return false;
2189 }
2190 };
2191
2192 class FakeCrxDownloader : public CrxDownloader {
2193 public:
dchengd0fc6aa92016-04-22 18:03:122194 static std::unique_ptr<CrxDownloader> Create(
asargente90363b2015-09-09 22:40:072195 bool is_background_download,
2196 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102197 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122198 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
asargente90363b2015-09-09 22:40:072199 }
2200
2201 private:
sorin74e70672016-02-03 03:13:102202 FakeCrxDownloader()
2203 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
asargente90363b2015-09-09 22:40:072204 ~FakeCrxDownloader() override {}
2205
2206 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2207 };
2208
2209 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dchengd0fc6aa92016-04-22 18:03:122210 config(), base::WrapUnique(new FakePingManagerImpl(config())),
asargente90363b2015-09-09 22:40:072211 &FakeUpdateChecker::Create, &FakeCrxDownloader::Create));
2212
2213 std::vector<std::string> empty_id_list;
2214 base::RunLoop runloop;
2215 update_client->Update(
2216 empty_id_list, base::Bind(&DataCallbackFake::Callback),
2217 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2218 runloop.Run();
asargente90363b2015-09-09 22:40:072219}
2220
sorin805aa03112016-01-14 23:01:312221TEST_F(UpdateClientTest, SendUninstallPing) {
2222 class FakeUpdateChecker : public UpdateChecker {
2223 public:
dchengd0fc6aa92016-04-22 18:03:122224 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572225 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492226 PersistedData* metadata) {
sorin805aa03112016-01-14 23:01:312227 return nullptr;
2228 }
2229
2230 bool CheckForUpdates(
2231 const std::vector<CrxUpdateItem*>& items_to_check,
2232 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362233 bool enabled_component_updates,
sorin805aa03112016-01-14 23:01:312234 const UpdateCheckCallback& update_check_callback) override {
2235 return false;
2236 }
2237 };
2238
2239 class FakeCrxDownloader : public CrxDownloader {
2240 public:
dchengd0fc6aa92016-04-22 18:03:122241 static std::unique_ptr<CrxDownloader> Create(
sorin805aa03112016-01-14 23:01:312242 bool is_background_download,
2243 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102244 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
sorin805aa03112016-01-14 23:01:312245 return nullptr;
2246 }
2247
2248 private:
sorin74e70672016-02-03 03:13:102249 FakeCrxDownloader()
2250 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin805aa03112016-01-14 23:01:312251 ~FakeCrxDownloader() override {}
2252
2253 void DoStartDownload(const GURL& url) override {}
2254 };
2255
2256 class FakePingManager : public FakePingManagerImpl {
2257 public:
2258 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2259 : FakePingManagerImpl(config) {}
2260 ~FakePingManager() override {
2261 const auto& ping_items = items();
2262 EXPECT_EQ(1U, ping_items.size());
2263 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:002264 EXPECT_EQ(base::Version("1.0"), ping_items[0].previous_version);
2265 EXPECT_EQ(base::Version("0.0"), ping_items[0].next_version);
sorin805aa03112016-01-14 23:01:312266 EXPECT_EQ(10, ping_items[0].extra_code1);
2267 }
2268 };
2269
dchengd0fc6aa92016-04-22 18:03:122270 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin805aa03112016-01-14 23:01:312271 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2272 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2273 &FakeCrxDownloader::Create));
2274
2275 update_client->SendUninstallPing("jebgalgnebhfojomionfpkfelancnnkf",
2276 base::Version("1.0"), 10);
2277}
2278
sorinfccbf2d2016-04-04 20:34:342279TEST_F(UpdateClientTest, RetryAfter) {
2280 class DataCallbackFake {
2281 public:
2282 static void Callback(const std::vector<std::string>& ids,
2283 std::vector<CrxComponent>* components) {
2284 CrxComponent crx;
2285 crx.name = "test_jebg";
2286 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122287 crx.version = base::Version("0.9");
sorinfccbf2d2016-04-04 20:34:342288 crx.installer = new TestInstaller;
2289 components->push_back(crx);
2290 }
2291 };
2292
2293 class CompletionCallbackFake {
2294 public:
2295 static void Callback(const base::Closure& quit_closure, int error) {
2296 static int num_call = 0;
2297 ++num_call;
2298
2299 EXPECT_LE(num_call, 4);
2300
2301 if (num_call == 1) {
2302 EXPECT_EQ(0, error);
2303 } else if (num_call == 2) {
2304 // This request is throttled since the update engine received a
2305 // positive |retry_after_sec| value in the update check response.
2306 EXPECT_EQ(Error::ERROR_UPDATE_RETRY_LATER, error);
2307 } else if (num_call == 3) {
2308 // This request is a foreground Install, which is never throttled.
2309 // The update engine received a |retry_after_sec| value of 0, which
2310 // resets the throttling.
2311 EXPECT_EQ(0, error);
2312 } else if (num_call == 4) {
2313 // This request succeeds since there is no throttling in effect.
2314 EXPECT_EQ(0, error);
2315 }
2316
2317 quit_closure.Run();
2318 }
2319 };
2320
2321 class FakeUpdateChecker : public UpdateChecker {
2322 public:
dchengd0fc6aa92016-04-22 18:03:122323 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572324 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492325 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122326 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorinfccbf2d2016-04-04 20:34:342327 }
2328
2329 bool CheckForUpdates(
2330 const std::vector<CrxUpdateItem*>& items_to_check,
2331 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362332 bool enabled_component_updates,
sorinfccbf2d2016-04-04 20:34:342333 const UpdateCheckCallback& update_check_callback) override {
2334 static int num_call = 0;
2335 ++num_call;
2336
2337 EXPECT_LE(num_call, 3);
2338
2339 int retry_after_sec(0);
2340 if (num_call == 1) {
2341 // Throttle the next call.
2342 retry_after_sec = 60 * 60; // 1 hour.
2343 }
2344
2345 base::ThreadTaskRunnerHandle::Get()->PostTask(
2346 FROM_HERE, base::Bind(update_check_callback, 0,
2347 UpdateResponse::Results(), retry_after_sec));
2348 return true;
2349 }
2350 };
2351
2352 class FakeCrxDownloader : public CrxDownloader {
2353 public:
dchengd0fc6aa92016-04-22 18:03:122354 static std::unique_ptr<CrxDownloader> Create(
sorinfccbf2d2016-04-04 20:34:342355 bool is_background_download,
2356 net::URLRequestContextGetter* context_getter,
2357 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122358 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorinfccbf2d2016-04-04 20:34:342359 }
2360
2361 private:
2362 FakeCrxDownloader()
2363 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
2364 ~FakeCrxDownloader() override {}
2365
2366 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2367 };
2368
2369 class FakePingManager : public FakePingManagerImpl {
2370 public:
2371 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2372 : FakePingManagerImpl(config) {}
2373 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
2374 };
2375
dchengd0fc6aa92016-04-22 18:03:122376 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorinfccbf2d2016-04-04 20:34:342377 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2378 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2379 &FakeCrxDownloader::Create));
2380
2381 MockObserver observer;
2382
2383 InSequence seq;
2384 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2385 "jebgalgnebhfojomionfpkfelancnnkf"))
2386 .Times(1);
2387 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2388 "jebgalgnebhfojomionfpkfelancnnkf"))
2389 .Times(1);
2390 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2391 "jebgalgnebhfojomionfpkfelancnnkf"))
2392 .Times(1);
2393 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2394 "jebgalgnebhfojomionfpkfelancnnkf"))
2395 .Times(1);
2396 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2397 "jebgalgnebhfojomionfpkfelancnnkf"))
2398 .Times(1);
2399 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2400 "jebgalgnebhfojomionfpkfelancnnkf"))
2401 .Times(1);
2402
2403 update_client->AddObserver(&observer);
2404
2405 std::vector<std::string> ids;
2406 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
2407
2408 {
2409 // The engine handles this Update call but responds with a valid
2410 // |retry_after_sec|, which causes subsequent calls to fail.
2411 base::RunLoop runloop;
2412 update_client->Update(
2413 ids, base::Bind(&DataCallbackFake::Callback),
2414 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2415 runloop.Run();
2416 }
2417
2418 {
2419 // This call will result in a completion callback invoked with
2420 // Error::ERROR_UPDATE_RETRY_LATER.
2421 base::RunLoop runloop;
2422 update_client->Update(
2423 ids, base::Bind(&DataCallbackFake::Callback),
2424 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2425 runloop.Run();
2426 }
2427
2428 {
2429 // The Install call is handled, and the throttling is reset due to
2430 // the value of |retry_after_sec| in the completion callback.
2431 base::RunLoop runloop;
2432 update_client->Install(
2433 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2434 base::Bind(&DataCallbackFake::Callback),
2435 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2436 runloop.Run();
2437 }
2438
2439 {
2440 // This call succeeds.
2441 base::RunLoop runloop;
2442 update_client->Update(
2443 ids, base::Bind(&DataCallbackFake::Callback),
2444 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2445 runloop.Run();
2446 }
2447
2448 update_client->RemoveObserver(&observer);
2449}
2450
sorine84ff702016-08-04 01:22:022451// Tests the update check for two CRXs scenario. The first component supports
2452// the group policy to enable updates, and has its updates disabled. The second
2453// component has an update. The server does not honor the "updatedisabled"
2454// attribute and returns updates for both components.
2455TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
2456 class DataCallbackFake {
2457 public:
2458 static void Callback(const std::vector<std::string>& ids,
2459 std::vector<CrxComponent>* components) {
2460 CrxComponent crx1;
2461 crx1.name = "test_jebg";
2462 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122463 crx1.version = base::Version("0.9");
sorine84ff702016-08-04 01:22:022464 crx1.installer = new TestInstaller;
2465 crx1.supports_group_policy_enable_component_updates = true;
2466
2467 CrxComponent crx2;
2468 crx2.name = "test_ihfo";
2469 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:122470 crx2.version = base::Version("0.8");
sorine84ff702016-08-04 01:22:022471 crx2.installer = new TestInstaller;
2472
2473 components->push_back(crx1);
2474 components->push_back(crx2);
2475 }
2476 };
2477
2478 class CompletionCallbackFake {
2479 public:
2480 static void Callback(const base::Closure& quit_closure, int error) {
2481 EXPECT_EQ(0, error);
2482 quit_closure.Run();
2483 }
2484 };
2485
2486 class FakeUpdateChecker : public UpdateChecker {
2487 public:
2488 static std::unique_ptr<UpdateChecker> Create(
2489 const scoped_refptr<Configurator>& config,
2490 PersistedData* metadata) {
2491 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
2492 }
2493
2494 bool CheckForUpdates(
2495 const std::vector<CrxUpdateItem*>& items_to_check,
2496 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362497 bool enabled_component_updates,
sorine84ff702016-08-04 01:22:022498 const UpdateCheckCallback& update_check_callback) override {
2499 /*
2500 Fake the following response:
2501
2502 <?xml version='1.0' encoding='UTF-8'?>
2503 <response protocol='3.0'>
2504 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2505 <updatecheck status='ok'>
2506 <urls>
2507 <url codebase='http://localhost/download/'/>
2508 </urls>
2509 <manifest version='1.0' prodversionmin='11.0.1.0'>
2510 <packages>
2511 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
2512 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
2513 7c9b12cb7cc067667bde87'/>
2514 </packages>
2515 </manifest>
2516 </updatecheck>
2517 </app>
2518 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
2519 <updatecheck status='ok'>
2520 <urls>
2521 <url codebase='http://localhost/download/'/>
2522 </urls>
2523 <manifest version='1.0' prodversionmin='11.0.1.0'>
2524 <packages>
2525 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
2526 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
2527 309f156ea6d27229c0b3f9'/>
2528 </packages>
2529 </manifest>
2530 </updatecheck>
2531 </app>
2532 </response>
2533 */
sorin590921d2016-08-11 23:48:362534
2535 // UpdateClient reads the state of |enabled_component_updates| from the
2536 // configurator instance, persists its value in the corresponding
2537 // update context, and propagates it down to each of the update actions,
2538 // and further down to the UpdateChecker instance.
2539 EXPECT_FALSE(enabled_component_updates);
2540
sorine84ff702016-08-04 01:22:022541 UpdateResponse::Result::Manifest::Package package1;
2542 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
2543 package1.hash_sha256 =
2544 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
2545
2546 UpdateResponse::Result result1;
2547 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
2548 result1.crx_urls.push_back(GURL("http://localhost/download/"));
2549 result1.manifest.version = "1.0";
2550 result1.manifest.browser_min_version = "11.0.1.0";
2551 result1.manifest.packages.push_back(package1);
2552
2553 UpdateResponse::Result::Manifest::Package package2;
2554 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
2555 package2.hash_sha256 =
2556 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
2557
2558 UpdateResponse::Result result2;
2559 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
2560 result2.crx_urls.push_back(GURL("http://localhost/download/"));
2561 result2.manifest.version = "1.0";
2562 result2.manifest.browser_min_version = "11.0.1.0";
2563 result2.manifest.packages.push_back(package2);
2564
2565 UpdateResponse::Results results;
2566 results.list.push_back(result1);
2567 results.list.push_back(result2);
2568
2569 base::ThreadTaskRunnerHandle::Get()->PostTask(
2570 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
2571 return true;
2572 }
2573 };
2574
2575 class FakeCrxDownloader : public CrxDownloader {
2576 public:
2577 static std::unique_ptr<CrxDownloader> Create(
2578 bool is_background_download,
2579 net::URLRequestContextGetter* context_getter,
2580 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
2581 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
2582 }
2583
2584 private:
2585 FakeCrxDownloader()
2586 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
2587 ~FakeCrxDownloader() override {}
2588
2589 void DoStartDownload(const GURL& url) override {
2590 DownloadMetrics download_metrics;
2591 FilePath path;
2592 Result result;
2593 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
2594 download_metrics.url = url;
2595 download_metrics.downloader = DownloadMetrics::kNone;
2596 download_metrics.error = 0;
2597 download_metrics.downloaded_bytes = 53638;
2598 download_metrics.total_bytes = 53638;
2599 download_metrics.download_time_ms = 2000;
2600
2601 EXPECT_TRUE(MakeTestFile(
2602 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
2603
2604 result.error = 0;
2605 result.response = path;
2606 result.downloaded_bytes = 53638;
2607 result.total_bytes = 53638;
2608 } else {
2609 NOTREACHED();
2610 }
2611
2612 base::ThreadTaskRunnerHandle::Get()->PostTask(
2613 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
2614 base::Unretained(this), result));
2615
2616 base::ThreadTaskRunnerHandle::Get()->PostTask(
2617 FROM_HERE,
2618 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
2619 base::Unretained(this), true, result, download_metrics));
2620 }
2621 };
2622
2623 class FakePingManager : public FakePingManagerImpl {
2624 public:
2625 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2626 : FakePingManagerImpl(config) {}
2627 ~FakePingManager() override {
2628 const auto& ping_items = items();
2629 EXPECT_EQ(2U, ping_items.size());
2630 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
2631 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
2632 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
2633 EXPECT_EQ(4, ping_items[0].error_category);
2634 EXPECT_EQ(2, ping_items[0].error_code);
2635 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
2636 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
2637 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
2638 EXPECT_EQ(0, ping_items[1].error_category);
2639 EXPECT_EQ(0, ping_items[1].error_code);
2640 }
2641 };
2642
2643 // Disables updates for the components declaring support for the group policy.
2644 config()->SetEnabledComponentUpdates(false);
2645 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
2646 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2647 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2648 &FakeCrxDownloader::Create));
2649
2650 MockObserver observer;
2651 {
2652 InSequence seq;
2653 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2654 "jebgalgnebhfojomionfpkfelancnnkf"))
2655 .Times(1);
2656 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2657 "jebgalgnebhfojomionfpkfelancnnkf"))
2658 .Times(1);
2659 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2660 "jebgalgnebhfojomionfpkfelancnnkf"))
2661 .Times(1);
2662 }
2663 {
2664 InSequence seq;
2665 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2666 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2667 .Times(1);
2668 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2669 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2670 .Times(1);
2671 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
2672 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2673 .Times(1);
2674 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
2675 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2676 .Times(1);
2677 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2678 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2679 .Times(1);
2680 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2681 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2682 .Times(1);
2683 }
2684
2685 update_client->AddObserver(&observer);
2686
2687 std::vector<std::string> ids;
2688 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
2689 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
2690
2691 update_client->Update(
2692 ids, base::Bind(&DataCallbackFake::Callback),
2693 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2694
2695 RunThreads();
2696
2697 update_client->RemoveObserver(&observer);
2698}
2699
sorin9797aba2015-04-17 17:15:032700} // namespace update_client