blob: ca949b62f7666974919fb761cfd369f9a137fed3 [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"
sorin7b8650522016-11-02 18:23:4130#include "components/update_client/update_client_errors.h"
sorin9797aba2015-04-17 17:15:0331#include "components/update_client/update_client_internal.h"
sorin9797aba2015-04-17 17:15:0332#include "testing/gmock/include/gmock/gmock.h"
33#include "testing/gtest/include/gtest/gtest.h"
34#include "url/gurl.h"
35
36namespace update_client {
37
38namespace {
39
40using base::FilePath;
41
42// Makes a copy of the file specified by |from_path| in a temporary directory
43// and returns the path of the copy. Returns true if successful. Cleans up if
44// there was an error creating the copy.
45bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
46 FilePath temp_dir;
47 bool result =
48 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir);
49 if (!result)
50 return false;
51
52 FilePath temp_file;
53 result = CreateTemporaryFileInDir(temp_dir, &temp_file);
54 if (!result)
55 return false;
56
57 result = CopyFile(from_path, temp_file);
58 if (!result) {
59 DeleteFile(temp_file, false);
60 return false;
61 }
62
63 *to_path = temp_file;
64 return true;
65}
66
67using Events = UpdateClient::Observer::Events;
68
69class MockObserver : public UpdateClient::Observer {
70 public:
71 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
72};
73
sorin7c717622015-05-26 19:59:0974class OnDemandTester {
75 public:
76 OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
77 bool expected_value);
78
79 void CheckOnDemand(Events event, const std::string&);
80
81 private:
82 const scoped_refptr<UpdateClient> update_client_;
83 const bool expected_value_;
84};
85
86OnDemandTester::OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
87 bool expected_value)
88 : update_client_(update_client), expected_value_(expected_value) {
89}
90
91void OnDemandTester::CheckOnDemand(Events event, const std::string& id) {
92 if (event == Events::COMPONENT_CHECKING_FOR_UPDATES) {
93 CrxUpdateItem update_item;
94 EXPECT_TRUE(update_client_->GetCrxUpdateState(id, &update_item));
95 EXPECT_EQ(update_item.on_demand, expected_value_);
96 }
97}
98
sorin9797aba2015-04-17 17:15:0399class FakePingManagerImpl : public PingManager {
100 public:
sorin958b5d32016-01-09 02:00:20101 explicit FakePingManagerImpl(const scoped_refptr<Configurator>& config);
sorin9797aba2015-04-17 17:15:03102 ~FakePingManagerImpl() override;
103
sorinfccbf2d2016-04-04 20:34:34104 bool SendPing(const CrxUpdateItem* item) override;
sorin9797aba2015-04-17 17:15:03105
106 const std::vector<CrxUpdateItem>& items() const;
107
108 private:
109 std::vector<CrxUpdateItem> items_;
110 DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl);
111};
112
sorin958b5d32016-01-09 02:00:20113FakePingManagerImpl::FakePingManagerImpl(
114 const scoped_refptr<Configurator>& config)
115 : PingManager(config) {}
sorin9797aba2015-04-17 17:15:03116
117FakePingManagerImpl::~FakePingManagerImpl() {
118}
119
sorinfccbf2d2016-04-04 20:34:34120bool FakePingManagerImpl::SendPing(const CrxUpdateItem* item) {
sorin9797aba2015-04-17 17:15:03121 items_.push_back(*item);
sorinfccbf2d2016-04-04 20:34:34122 return true;
sorin9797aba2015-04-17 17:15:03123}
124
125const std::vector<CrxUpdateItem>& FakePingManagerImpl::items() const {
126 return items_;
127}
128
129} // namespace
130
131using ::testing::_;
132using ::testing::AnyNumber;
133using ::testing::DoAll;
134using ::testing::InSequence;
135using ::testing::Invoke;
136using ::testing::Mock;
137using ::testing::Return;
138
sorin9797aba2015-04-17 17:15:03139using std::string;
140
141class UpdateClientTest : public testing::Test {
142 public:
143 UpdateClientTest();
144 ~UpdateClientTest() override;
145
sorin9797aba2015-04-17 17:15:03146 protected:
147 void RunThreads();
148
149 // Returns the full path to a test file.
150 static base::FilePath TestFilePath(const char* file);
151
sorine84ff702016-08-04 01:22:02152 scoped_refptr<update_client::TestConfigurator> config() { return config_; }
wafflese7dff732016-04-15 23:51:49153 update_client::PersistedData* metadata() { return metadata_.get(); }
sorin9797aba2015-04-17 17:15:03154
sorinf9f4834d2015-04-28 17:15:02155 base::Closure quit_closure() { return quit_closure_; }
156
157 private:
158 static const int kNumWorkerThreads_ = 2;
159
160 base::MessageLoopForUI message_loop_;
sorin9797aba2015-04-17 17:15:03161 base::RunLoop runloop_;
162 base::Closure quit_closure_;
163
dchengd0fc6aa92016-04-22 18:03:12164 std::unique_ptr<base::SequencedWorkerPoolOwner> worker_pool_;
sorin9797aba2015-04-17 17:15:03165
sorine84ff702016-08-04 01:22:02166 scoped_refptr<update_client::TestConfigurator> config_;
wafflesd2d9a332016-04-09 01:59:57167 std::unique_ptr<TestingPrefServiceSimple> pref_;
168 std::unique_ptr<update_client::PersistedData> metadata_;
sorinf9f4834d2015-04-28 17:15:02169
sorin9797aba2015-04-17 17:15:03170 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
171};
172
173UpdateClientTest::UpdateClientTest()
sorin85e68032015-05-27 19:50:51174 : worker_pool_(
175 new base::SequencedWorkerPoolOwner(kNumWorkerThreads_, "test")) {
sorinf9f4834d2015-04-28 17:15:02176 quit_closure_ = runloop_.QuitClosure();
177
sorin85e68032015-05-27 19:50:51178 auto pool = worker_pool_->pool();
sorinf9f4834d2015-04-28 17:15:02179 config_ = new TestConfigurator(
sorin85e68032015-05-27 19:50:51180 pool->GetSequencedTaskRunner(pool->GetSequenceToken()),
sorin7c717622015-05-26 19:59:09181 message_loop_.task_runner());
wafflesd2d9a332016-04-09 01:59:57182 pref_.reset(new TestingPrefServiceSimple());
183 PersistedData::RegisterPrefs(pref_->registry());
184 metadata_.reset(new PersistedData(pref_.get()));
sorin9797aba2015-04-17 17:15:03185}
186
187UpdateClientTest::~UpdateClientTest() {
sorin9797aba2015-04-17 17:15:03188}
189
190void UpdateClientTest::RunThreads() {
191 runloop_.Run();
192}
193
194base::FilePath UpdateClientTest::TestFilePath(const char* file) {
195 base::FilePath path;
196 PathService::Get(base::DIR_SOURCE_ROOT, &path);
197 return path.AppendASCII("components")
198 .AppendASCII("test")
199 .AppendASCII("data")
200 .AppendASCII("update_client")
201 .AppendASCII(file);
202}
203
204// Tests the scenario where one update check is done for one CRX. The CRX
205// has no update.
206TEST_F(UpdateClientTest, OneCrxNoUpdate) {
207 class DataCallbackFake {
208 public:
209 static void Callback(const std::vector<std::string>& ids,
210 std::vector<CrxComponent>* components) {
211 CrxComponent crx;
212 crx.name = "test_jebg";
213 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12214 crx.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03215 crx.installer = new TestInstaller;
216 components->push_back(crx);
217 }
218 };
219
220 class CompletionCallbackFake {
221 public:
sorin7b8650522016-11-02 18:23:41222 static void Callback(const base::Closure& quit_closure, Error error) {
223 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:03224 quit_closure.Run();
225 }
226 };
227
228 class FakeUpdateChecker : public UpdateChecker {
229 public:
dchengd0fc6aa92016-04-22 18:03:12230 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57231 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49232 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12233 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03234 }
235
236 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:00237 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
238 items_to_check,
sorin9797aba2015-04-17 17:15:03239 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36240 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03241 const UpdateCheckCallback& update_check_callback) override {
sorin590921d2016-08-11 23:48:36242 EXPECT_TRUE(enabled_component_updates);
sorin9797aba2015-04-17 17:15:03243 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:17244 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:34245 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin9797aba2015-04-17 17:15:03246 return true;
247 }
248 };
249
250 class FakeCrxDownloader : public CrxDownloader {
251 public:
dchengd0fc6aa92016-04-22 18:03:12252 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03253 bool is_background_download,
254 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10255 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12256 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03257 }
258
259 private:
sorin74e70672016-02-03 03:13:10260 FakeCrxDownloader()
261 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03262 ~FakeCrxDownloader() override {}
263
264 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
265 };
266
267 class FakePingManager : public FakePingManagerImpl {
268 public:
sorin958b5d32016-01-09 02:00:20269 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03270 : FakePingManagerImpl(config) {}
271 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
272 };
273
dchengd0fc6aa92016-04-22 18:03:12274 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09275 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17276 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03277 &FakeCrxDownloader::Create));
278
sorin7c717622015-05-26 19:59:09279 // Verify that calling Update does not set ondemand.
280 OnDemandTester ondemand_tester(update_client, false);
281
sorin9797aba2015-04-17 17:15:03282 MockObserver observer;
sorin7c717622015-05-26 19:59:09283 ON_CALL(observer, OnEvent(_, _))
284 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
285
sorin9797aba2015-04-17 17:15:03286 InSequence seq;
287 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
288 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
289 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
290 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
291
292 update_client->AddObserver(&observer);
293
294 std::vector<std::string> ids;
295 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
296
297 update_client->Update(
298 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02299 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03300
301 RunThreads();
302
303 update_client->RemoveObserver(&observer);
304}
305
306// Tests the scenario where two CRXs are checked for updates. On CRX has
307// an update, the other CRX does not.
308TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
309 class DataCallbackFake {
310 public:
311 static void Callback(const std::vector<std::string>& ids,
312 std::vector<CrxComponent>* components) {
313 CrxComponent crx1;
314 crx1.name = "test_jebg";
315 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12316 crx1.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03317 crx1.installer = new TestInstaller;
318
319 CrxComponent crx2;
320 crx2.name = "test_abag";
321 crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
pwnalldb0b72412016-08-19 21:39:12322 crx2.version = base::Version("2.2");
sorin9797aba2015-04-17 17:15:03323 crx2.installer = new TestInstaller;
324
325 components->push_back(crx1);
326 components->push_back(crx2);
327 }
328 };
329
330 class CompletionCallbackFake {
331 public:
sorin7b8650522016-11-02 18:23:41332 static void Callback(const base::Closure& quit_closure, Error error) {
333 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:03334 quit_closure.Run();
335 }
336 };
337
338 class FakeUpdateChecker : public UpdateChecker {
339 public:
dchengd0fc6aa92016-04-22 18:03:12340 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57341 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49342 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12343 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03344 }
345
346 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:00347 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
348 items_to_check,
sorin9797aba2015-04-17 17:15:03349 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36350 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03351 const UpdateCheckCallback& update_check_callback) override {
352 /*
353 Fake the following response:
354
355 <?xml version='1.0' encoding='UTF-8'?>
356 <response protocol='3.0'>
357 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
358 <updatecheck status='ok'>
359 <urls>
360 <url codebase='http://localhost/download/'/>
361 </urls>
362 <manifest version='1.0' prodversionmin='11.0.1.0'>
363 <packages>
sorin74e70672016-02-03 03:13:10364 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
365 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
366 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03367 </packages>
368 </manifest>
369 </updatecheck>
370 </app>
371 </response>
372 */
373 UpdateResponse::Result::Manifest::Package package;
374 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10375 package.hash_sha256 =
376 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03377
378 UpdateResponse::Result result;
379 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
380 result.crx_urls.push_back(GURL("http://localhost/download/"));
381 result.manifest.version = "1.0";
382 result.manifest.browser_min_version = "11.0.1.0";
383 result.manifest.packages.push_back(package);
384
385 UpdateResponse::Results results;
386 results.list.push_back(result);
387
388 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34389 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:03390 return true;
391 }
392 };
393
394 class FakeCrxDownloader : public CrxDownloader {
395 public:
dchengd0fc6aa92016-04-22 18:03:12396 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03397 bool is_background_download,
398 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10399 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12400 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03401 }
402
403 private:
sorin74e70672016-02-03 03:13:10404 FakeCrxDownloader()
405 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03406 ~FakeCrxDownloader() override {}
407
408 void DoStartDownload(const GURL& url) override {
409 DownloadMetrics download_metrics;
410 download_metrics.url = url;
411 download_metrics.downloader = DownloadMetrics::kNone;
412 download_metrics.error = 0;
413 download_metrics.downloaded_bytes = 1843;
414 download_metrics.total_bytes = 1843;
415 download_metrics.download_time_ms = 1000;
416
417 FilePath path;
418 EXPECT_TRUE(MakeTestFile(
419 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
420
421 Result result;
422 result.error = 0;
423 result.response = path;
424 result.downloaded_bytes = 1843;
425 result.total_bytes = 1843;
426
427 base::ThreadTaskRunnerHandle::Get()->PostTask(
428 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
429 base::Unretained(this), result));
430
431 base::ThreadTaskRunnerHandle::Get()->PostTask(
432 FROM_HERE,
433 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
434 base::Unretained(this), true, result, download_metrics));
435 }
436 };
437
438 class FakePingManager : public FakePingManagerImpl {
439 public:
sorin958b5d32016-01-09 02:00:20440 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03441 : FakePingManagerImpl(config) {}
442 ~FakePingManager() override {
443 const auto& ping_items = items();
444 EXPECT_EQ(1U, ping_items.size());
445 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00446 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
447 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:03448 EXPECT_EQ(0, ping_items[0].error_category);
449 EXPECT_EQ(0, ping_items[0].error_code);
450 }
451 };
452
dchengd0fc6aa92016-04-22 18:03:12453 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09454 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17455 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03456 &FakeCrxDownloader::Create));
457
458 MockObserver observer;
459 {
460 InSequence seq;
461 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
462 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
463 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
464 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
465 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
466 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
467 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
468 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
469 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
470 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
471 }
472 {
473 InSequence seq;
474 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
475 "abagagagagagagagagagagagagagagag")).Times(1);
476 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
477 "abagagagagagagagagagagagagagagag")).Times(1);
478 }
479
480 update_client->AddObserver(&observer);
481
482 std::vector<std::string> ids;
483 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
484 ids.push_back(std::string("abagagagagagagagagagagagagagagag"));
485
486 update_client->Update(
487 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02488 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03489
490 RunThreads();
491
492 update_client->RemoveObserver(&observer);
493}
494
495// Tests the update check for two CRXs scenario. Both CRXs have updates.
496TEST_F(UpdateClientTest, TwoCrxUpdate) {
497 class DataCallbackFake {
498 public:
499 static void Callback(const std::vector<std::string>& ids,
500 std::vector<CrxComponent>* components) {
501 CrxComponent crx1;
502 crx1.name = "test_jebg";
503 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12504 crx1.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:03505 crx1.installer = new TestInstaller;
506
507 CrxComponent crx2;
508 crx2.name = "test_ihfo";
509 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:12510 crx2.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:03511 crx2.installer = new TestInstaller;
512
513 components->push_back(crx1);
514 components->push_back(crx2);
515 }
516 };
517
518 class CompletionCallbackFake {
519 public:
sorin7b8650522016-11-02 18:23:41520 static void Callback(const base::Closure& quit_closure, Error error) {
521 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:03522 quit_closure.Run();
523 }
524 };
525
526 class FakeUpdateChecker : public UpdateChecker {
527 public:
dchengd0fc6aa92016-04-22 18:03:12528 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57529 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49530 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12531 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:03532 }
533
534 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:00535 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
536 items_to_check,
sorin9797aba2015-04-17 17:15:03537 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36538 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:03539 const UpdateCheckCallback& update_check_callback) override {
540 /*
541 Fake the following response:
542
543 <?xml version='1.0' encoding='UTF-8'?>
544 <response protocol='3.0'>
545 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
546 <updatecheck status='ok'>
547 <urls>
548 <url codebase='http://localhost/download/'/>
549 </urls>
550 <manifest version='1.0' prodversionmin='11.0.1.0'>
551 <packages>
sorin74e70672016-02-03 03:13:10552 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
553 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
554 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03555 </packages>
556 </manifest>
557 </updatecheck>
558 </app>
559 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
560 <updatecheck status='ok'>
561 <urls>
562 <url codebase='http://localhost/download/'/>
563 </urls>
564 <manifest version='1.0' prodversionmin='11.0.1.0'>
565 <packages>
sorin74e70672016-02-03 03:13:10566 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
567 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
568 309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:03569 </packages>
570 </manifest>
571 </updatecheck>
572 </app>
573 </response>
574 */
575 UpdateResponse::Result::Manifest::Package package1;
576 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10577 package1.hash_sha256 =
578 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03579
580 UpdateResponse::Result result1;
581 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
582 result1.crx_urls.push_back(GURL("http://localhost/download/"));
583 result1.manifest.version = "1.0";
584 result1.manifest.browser_min_version = "11.0.1.0";
585 result1.manifest.packages.push_back(package1);
586
587 UpdateResponse::Result::Manifest::Package package2;
588 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:10589 package2.hash_sha256 =
590 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:03591
592 UpdateResponse::Result result2;
593 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
594 result2.crx_urls.push_back(GURL("http://localhost/download/"));
595 result2.manifest.version = "1.0";
596 result2.manifest.browser_min_version = "11.0.1.0";
597 result2.manifest.packages.push_back(package2);
598
599 UpdateResponse::Results results;
600 results.list.push_back(result1);
601 results.list.push_back(result2);
602
603 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34604 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:03605 return true;
606 }
607 };
608
609 class FakeCrxDownloader : public CrxDownloader {
610 public:
dchengd0fc6aa92016-04-22 18:03:12611 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03612 bool is_background_download,
613 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10614 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12615 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:03616 }
617
618 private:
sorin74e70672016-02-03 03:13:10619 FakeCrxDownloader()
620 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:03621 ~FakeCrxDownloader() override {}
622
623 void DoStartDownload(const GURL& url) override {
624 DownloadMetrics download_metrics;
625 FilePath path;
626 Result result;
627 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
628 download_metrics.url = url;
629 download_metrics.downloader = DownloadMetrics::kNone;
630 download_metrics.error = 0;
631 download_metrics.downloaded_bytes = 1843;
632 download_metrics.total_bytes = 1843;
633 download_metrics.download_time_ms = 1000;
634
635 EXPECT_TRUE(MakeTestFile(
636 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
637
638 result.error = 0;
639 result.response = path;
640 result.downloaded_bytes = 1843;
641 result.total_bytes = 1843;
642 } else if (url.path() ==
643 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
644 download_metrics.url = url;
645 download_metrics.downloader = DownloadMetrics::kNone;
646 download_metrics.error = 0;
647 download_metrics.downloaded_bytes = 53638;
648 download_metrics.total_bytes = 53638;
649 download_metrics.download_time_ms = 2000;
650
651 EXPECT_TRUE(MakeTestFile(
652 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
653
654 result.error = 0;
655 result.response = path;
656 result.downloaded_bytes = 53638;
657 result.total_bytes = 53638;
658 } else {
659 NOTREACHED();
660 }
661
662 base::ThreadTaskRunnerHandle::Get()->PostTask(
663 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
664 base::Unretained(this), result));
665
666 base::ThreadTaskRunnerHandle::Get()->PostTask(
667 FROM_HERE,
668 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
669 base::Unretained(this), true, result, download_metrics));
670 }
671 };
672
673 class FakePingManager : public FakePingManagerImpl {
674 public:
sorin958b5d32016-01-09 02:00:20675 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:03676 : FakePingManagerImpl(config) {}
677 ~FakePingManager() override {
678 const auto& ping_items = items();
679 EXPECT_EQ(2U, ping_items.size());
680 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00681 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
682 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:03683 EXPECT_EQ(0, ping_items[0].error_category);
684 EXPECT_EQ(0, ping_items[0].error_code);
685 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:00686 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
687 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:03688 EXPECT_EQ(0, ping_items[1].error_category);
689 EXPECT_EQ(0, ping_items[1].error_code);
690 }
691 };
692
dchengd0fc6aa92016-04-22 18:03:12693 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:09694 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17695 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:03696 &FakeCrxDownloader::Create));
697
698 MockObserver observer;
699 {
700 InSequence seq;
701 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
702 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
703 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
704 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
705 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
706 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
707 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
708 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
709 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
710 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
711 }
712 {
713 InSequence seq;
714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
715 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
716 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
717 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
718 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
719 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
720 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
721 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
722 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
723 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
724 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
725 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
726 }
727
728 update_client->AddObserver(&observer);
729
730 std::vector<std::string> ids;
731 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
732 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
733
734 update_client->Update(
735 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:02736 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03737
738 RunThreads();
739
740 update_client->RemoveObserver(&observer);
741}
742
sorin6bb8de42015-06-03 00:23:27743// Tests the scenario where there is a download timeout for the first
744// CRX. The update for the first CRX fails. The update client waits before
745// attempting the update for the second CRX. This update succeeds.
746TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
747 class DataCallbackFake {
748 public:
749 static void Callback(const std::vector<std::string>& ids,
750 std::vector<CrxComponent>* components) {
751 CrxComponent crx1;
752 crx1.name = "test_jebg";
753 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:12754 crx1.version = base::Version("0.9");
sorin6bb8de42015-06-03 00:23:27755 crx1.installer = new TestInstaller;
756
757 CrxComponent crx2;
758 crx2.name = "test_ihfo";
759 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:12760 crx2.version = base::Version("0.8");
sorin6bb8de42015-06-03 00:23:27761 crx2.installer = new TestInstaller;
762
763 components->push_back(crx1);
764 components->push_back(crx2);
765 }
766 };
767
768 class CompletionCallbackFake {
769 public:
sorin7b8650522016-11-02 18:23:41770 static void Callback(const base::Closure& quit_closure, Error error) {
771 EXPECT_EQ(Error::NONE, error);
sorin6bb8de42015-06-03 00:23:27772 quit_closure.Run();
773 }
774 };
775
776 class FakeUpdateChecker : public UpdateChecker {
777 public:
dchengd0fc6aa92016-04-22 18:03:12778 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:57779 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:49780 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:12781 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin6bb8de42015-06-03 00:23:27782 }
783
784 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:00785 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
786 items_to_check,
sorin6bb8de42015-06-03 00:23:27787 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:36788 bool enabled_component_updates,
sorin6bb8de42015-06-03 00:23:27789 const UpdateCheckCallback& update_check_callback) override {
790 /*
791 Fake the following response:
792
793 <?xml version='1.0' encoding='UTF-8'?>
794 <response protocol='3.0'>
795 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
796 <updatecheck status='ok'>
797 <urls>
798 <url codebase='http://localhost/download/'/>
799 </urls>
800 <manifest version='1.0' prodversionmin='11.0.1.0'>
801 <packages>
sorin74e70672016-02-03 03:13:10802 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
803 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
804 7c9b12cb7cc067667bde87'/>
sorin6bb8de42015-06-03 00:23:27805 </packages>
806 </manifest>
807 </updatecheck>
808 </app>
809 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
810 <updatecheck status='ok'>
811 <urls>
812 <url codebase='http://localhost/download/'/>
813 </urls>
814 <manifest version='1.0' prodversionmin='11.0.1.0'>
815 <packages>
sorin74e70672016-02-03 03:13:10816 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
817 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
818 309f156ea6d27229c0b3f9'/>
sorin6bb8de42015-06-03 00:23:27819 </packages>
820 </manifest>
821 </updatecheck>
822 </app>
823 </response>
824 */
825 UpdateResponse::Result::Manifest::Package package1;
826 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:10827 package1.hash_sha256 =
828 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin6bb8de42015-06-03 00:23:27829
830 UpdateResponse::Result result1;
831 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
832 result1.crx_urls.push_back(GURL("http://localhost/download/"));
833 result1.manifest.version = "1.0";
834 result1.manifest.browser_min_version = "11.0.1.0";
835 result1.manifest.packages.push_back(package1);
836
837 UpdateResponse::Result::Manifest::Package package2;
838 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:10839 package2.hash_sha256 =
840 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin6bb8de42015-06-03 00:23:27841
842 UpdateResponse::Result result2;
843 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
844 result2.crx_urls.push_back(GURL("http://localhost/download/"));
845 result2.manifest.version = "1.0";
846 result2.manifest.browser_min_version = "11.0.1.0";
847 result2.manifest.packages.push_back(package2);
848
849 UpdateResponse::Results results;
850 results.list.push_back(result1);
851 results.list.push_back(result2);
852
853 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:34854 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin6bb8de42015-06-03 00:23:27855 return true;
856 }
857 };
858
859 class FakeCrxDownloader : public CrxDownloader {
860 public:
dchengd0fc6aa92016-04-22 18:03:12861 static std::unique_ptr<CrxDownloader> Create(
sorin6bb8de42015-06-03 00:23:27862 bool is_background_download,
863 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:10864 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:12865 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin6bb8de42015-06-03 00:23:27866 }
867
868 private:
sorin74e70672016-02-03 03:13:10869 FakeCrxDownloader()
870 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin6bb8de42015-06-03 00:23:27871 ~FakeCrxDownloader() override {}
872
873 void DoStartDownload(const GURL& url) override {
874 DownloadMetrics download_metrics;
875 FilePath path;
876 Result result;
877 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
878 download_metrics.url = url;
879 download_metrics.downloader = DownloadMetrics::kNone;
880 download_metrics.error = -118;
881 download_metrics.downloaded_bytes = 0;
882 download_metrics.total_bytes = 0;
883 download_metrics.download_time_ms = 1000;
884
885 EXPECT_TRUE(MakeTestFile(
886 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
887
888 result.error = -118;
889 result.response = path;
890 result.downloaded_bytes = 0;
891 result.total_bytes = 0;
892 } else if (url.path() ==
893 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
894 download_metrics.url = url;
895 download_metrics.downloader = DownloadMetrics::kNone;
896 download_metrics.error = 0;
897 download_metrics.downloaded_bytes = 53638;
898 download_metrics.total_bytes = 53638;
899 download_metrics.download_time_ms = 2000;
900
901 EXPECT_TRUE(MakeTestFile(
902 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
903
904 result.error = 0;
905 result.response = path;
906 result.downloaded_bytes = 53638;
907 result.total_bytes = 53638;
908 } else {
909 NOTREACHED();
910 }
911
912 base::ThreadTaskRunnerHandle::Get()->PostTask(
913 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
914 base::Unretained(this), result));
915
916 base::ThreadTaskRunnerHandle::Get()->PostTask(
917 FROM_HERE,
918 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
919 base::Unretained(this), true, result, download_metrics));
920 }
921 };
922
923 class FakePingManager : public FakePingManagerImpl {
924 public:
sorin958b5d32016-01-09 02:00:20925 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin6bb8de42015-06-03 00:23:27926 : FakePingManagerImpl(config) {}
927 ~FakePingManager() override {
928 const auto& ping_items = items();
929 EXPECT_EQ(2U, ping_items.size());
930 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:00931 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
932 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin6bb8de42015-06-03 00:23:27933 EXPECT_EQ(1, ping_items[0].error_category); // Network error.
934 EXPECT_EQ(-118, ping_items[0].error_code);
935 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:00936 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
937 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
sorin6bb8de42015-06-03 00:23:27938 EXPECT_EQ(0, ping_items[1].error_category);
939 EXPECT_EQ(0, ping_items[1].error_code);
940 }
941 };
942
dchengd0fc6aa92016-04-22 18:03:12943 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin6bb8de42015-06-03 00:23:27944 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:17945 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin6bb8de42015-06-03 00:23:27946 &FakeCrxDownloader::Create));
947
948 MockObserver observer;
949 {
950 InSequence seq;
951 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
952 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
953 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
954 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
955 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
956 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
957 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
958 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
959 }
960 {
961 InSequence seq;
962 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
963 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
964 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
965 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
966 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
967 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
968 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
969 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
970 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
971 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
972 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
973 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
974 }
975
976 update_client->AddObserver(&observer);
977
978 std::vector<std::string> ids;
979 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
980 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
981
982 update_client->Update(
983 ids, base::Bind(&DataCallbackFake::Callback),
984 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
985
986 RunThreads();
987
988 update_client->RemoveObserver(&observer);
sorin6bb8de42015-06-03 00:23:27989}
990
sorin9797aba2015-04-17 17:15:03991// Tests the differential update scenario for one CRX.
992TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
993 class DataCallbackFake {
994 public:
995 static void Callback(const std::vector<std::string>& ids,
996 std::vector<CrxComponent>* components) {
997 static int num_calls = 0;
998
999 // Must use the same stateful installer object.
1000 static scoped_refptr<CrxInstaller> installer(
1001 new VersionedTestInstaller());
1002
1003 ++num_calls;
1004
1005 CrxComponent crx;
1006 crx.name = "test_ihfo";
1007 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
1008 crx.installer = installer;
1009 if (num_calls == 1) {
pwnalldb0b72412016-08-19 21:39:121010 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031011 } else if (num_calls == 2) {
pwnalldb0b72412016-08-19 21:39:121012 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031013 } else {
1014 NOTREACHED();
1015 }
1016
1017 components->push_back(crx);
1018 }
1019 };
1020
1021 class CompletionCallbackFake {
1022 public:
sorin7b8650522016-11-02 18:23:411023 static void Callback(const base::Closure& quit_closure, Error error) {
1024 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:031025 quit_closure.Run();
1026 }
1027 };
1028
1029 class FakeUpdateChecker : public UpdateChecker {
1030 public:
dchengd0fc6aa92016-04-22 18:03:121031 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571032 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491033 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121034 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031035 }
1036
1037 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:001038 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
1039 items_to_check,
sorin9797aba2015-04-17 17:15:031040 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361041 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031042 const UpdateCheckCallback& update_check_callback) override {
1043 static int num_call = 0;
1044 ++num_call;
1045
1046 UpdateResponse::Results results;
1047
1048 if (num_call == 1) {
1049 /*
1050 Fake the following response:
1051 <?xml version='1.0' encoding='UTF-8'?>
1052 <response protocol='3.0'>
1053 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1054 <updatecheck status='ok'>
1055 <urls>
1056 <url codebase='http://localhost/download/'/>
1057 </urls>
1058 <manifest version='1.0' prodversionmin='11.0.1.0'>
1059 <packages>
sorin74e70672016-02-03 03:13:101060 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1061 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1062 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031063 </packages>
1064 </manifest>
1065 </updatecheck>
1066 </app>
1067 </response>
1068 */
1069 UpdateResponse::Result::Manifest::Package package;
1070 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101071 package.hash_sha256 =
1072 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031073 package.fingerprint = "1";
1074 UpdateResponse::Result result;
1075 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1076 result.crx_urls.push_back(GURL("http://localhost/download/"));
1077 result.manifest.version = "1.0";
1078 result.manifest.browser_min_version = "11.0.1.0";
1079 result.manifest.packages.push_back(package);
1080 results.list.push_back(result);
1081 } else if (num_call == 2) {
1082 /*
1083 Fake the following response:
1084 <?xml version='1.0' encoding='UTF-8'?>
1085 <response protocol='3.0'>
1086 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1087 <updatecheck status='ok'>
1088 <urls>
1089 <url codebase='http://localhost/download/'/>
1090 <url codebasediff='http://localhost/download/'/>
1091 </urls>
1092 <manifest version='2.0' prodversionmin='11.0.1.0'>
1093 <packages>
1094 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1095 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101096 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1097 0ecde26c262bad942b112990'
1098 fp='22'
1099 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261100 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031101 </packages>
1102 </manifest>
1103 </updatecheck>
1104 </app>
1105 </response>
1106 */
1107 UpdateResponse::Result::Manifest::Package package;
1108 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1109 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101110 package.hash_sha256 =
1111 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1112 package.hashdiff_sha256 =
1113 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031114 package.fingerprint = "22";
1115 UpdateResponse::Result result;
1116 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1117 result.crx_urls.push_back(GURL("http://localhost/download/"));
1118 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1119 result.manifest.version = "2.0";
1120 result.manifest.browser_min_version = "11.0.1.0";
1121 result.manifest.packages.push_back(package);
1122 results.list.push_back(result);
1123 } else {
1124 NOTREACHED();
1125 }
1126
1127 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341128 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031129 return true;
1130 }
1131 };
1132
1133 class FakeCrxDownloader : public CrxDownloader {
1134 public:
dchengd0fc6aa92016-04-22 18:03:121135 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031136 bool is_background_download,
1137 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101138 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121139 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031140 }
1141
1142 private:
sorin74e70672016-02-03 03:13:101143 FakeCrxDownloader()
1144 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031145 ~FakeCrxDownloader() override {}
1146
1147 void DoStartDownload(const GURL& url) override {
1148 DownloadMetrics download_metrics;
1149 FilePath path;
1150 Result result;
1151 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1152 download_metrics.url = url;
1153 download_metrics.downloader = DownloadMetrics::kNone;
1154 download_metrics.error = 0;
1155 download_metrics.downloaded_bytes = 53638;
1156 download_metrics.total_bytes = 53638;
1157 download_metrics.download_time_ms = 2000;
1158
1159 EXPECT_TRUE(MakeTestFile(
1160 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1161
1162 result.error = 0;
1163 result.response = path;
1164 result.downloaded_bytes = 53638;
1165 result.total_bytes = 53638;
1166 } else if (url.path() ==
1167 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1168 download_metrics.url = url;
1169 download_metrics.downloader = DownloadMetrics::kNone;
1170 download_metrics.error = 0;
1171 download_metrics.downloaded_bytes = 2105;
1172 download_metrics.total_bytes = 2105;
1173 download_metrics.download_time_ms = 1000;
1174
1175 EXPECT_TRUE(MakeTestFile(
1176 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1177
1178 result.error = 0;
1179 result.response = path;
1180 result.downloaded_bytes = 2105;
1181 result.total_bytes = 2105;
1182 } else {
1183 NOTREACHED();
1184 }
1185
1186 base::ThreadTaskRunnerHandle::Get()->PostTask(
1187 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1188 base::Unretained(this), result));
1189
1190 base::ThreadTaskRunnerHandle::Get()->PostTask(
1191 FROM_HERE,
1192 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1193 base::Unretained(this), true, result, download_metrics));
1194 }
1195 };
1196
1197 class FakePingManager : public FakePingManagerImpl {
1198 public:
sorin958b5d32016-01-09 02:00:201199 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031200 : FakePingManagerImpl(config) {}
1201 ~FakePingManager() override {
1202 const auto& ping_items = items();
1203 EXPECT_EQ(2U, ping_items.size());
1204 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001205 EXPECT_EQ(base::Version("0.8"), ping_items[0].previous_version);
1206 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031207 EXPECT_EQ(0, ping_items[0].error_category);
1208 EXPECT_EQ(0, ping_items[0].error_code);
1209 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:001210 EXPECT_EQ(base::Version("1.0"), ping_items[1].previous_version);
1211 EXPECT_EQ(base::Version("2.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:031212 EXPECT_EQ(0, ping_items[1].diff_error_category);
1213 EXPECT_EQ(0, ping_items[1].diff_error_code);
1214 }
1215 };
1216
dchengd0fc6aa92016-04-22 18:03:121217 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091218 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171219 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031220 &FakeCrxDownloader::Create));
1221
1222 MockObserver observer;
1223 {
1224 InSequence seq;
1225 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1226 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1227 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1228 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1229 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1230 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1231 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1232 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1233 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1234 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1235 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1236 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1237 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1238 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1239 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1240 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1241 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1242 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1243 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1244 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1245 }
1246
1247 update_client->AddObserver(&observer);
1248
1249 std::vector<std::string> ids;
1250 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
1251
1252 {
1253 base::RunLoop runloop;
1254 update_client->Update(
1255 ids, base::Bind(&DataCallbackFake::Callback),
1256 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1257 runloop.Run();
1258 }
1259
1260 {
1261 base::RunLoop runloop;
1262 update_client->Update(
1263 ids, base::Bind(&DataCallbackFake::Callback),
1264 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1265 runloop.Run();
1266 }
1267
1268 update_client->RemoveObserver(&observer);
1269}
1270
1271// Tests the update scenario for one CRX where the CRX installer returns
1272// an error.
1273TEST_F(UpdateClientTest, OneCrxInstallError) {
1274 class MockInstaller : public CrxInstaller {
1275 public:
1276 MOCK_METHOD1(OnUpdateError, void(int error));
1277 MOCK_METHOD2(Install,
1278 bool(const base::DictionaryValue& manifest,
1279 const base::FilePath& unpack_path));
1280 MOCK_METHOD2(GetInstalledFile,
1281 bool(const std::string& file, base::FilePath* installed_file));
1282 MOCK_METHOD0(Uninstall, bool());
1283
1284 static void OnInstall(const base::DictionaryValue& manifest,
1285 const base::FilePath& unpack_path) {
1286 base::DeleteFile(unpack_path, true);
1287 }
1288
1289 protected:
1290 ~MockInstaller() override {}
1291 };
1292
1293 class DataCallbackFake {
1294 public:
1295 static void Callback(const std::vector<std::string>& ids,
1296 std::vector<CrxComponent>* components) {
1297 scoped_refptr<MockInstaller> installer(new MockInstaller());
1298
1299 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
1300 EXPECT_CALL(*installer, Install(_, _))
1301 .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false)));
1302 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
1303 EXPECT_CALL(*installer, Uninstall()).Times(0);
1304
1305 CrxComponent crx;
1306 crx.name = "test_jebg";
1307 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121308 crx.version = base::Version("0.9");
sorin9797aba2015-04-17 17:15:031309 crx.installer = installer;
1310 components->push_back(crx);
1311 }
1312 };
1313
1314 class CompletionCallbackFake {
1315 public:
sorin7b8650522016-11-02 18:23:411316 static void Callback(const base::Closure& quit_closure, Error error) {
1317 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:031318 quit_closure.Run();
1319 }
1320 };
1321
1322 class FakeUpdateChecker : public UpdateChecker {
1323 public:
dchengd0fc6aa92016-04-22 18:03:121324 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571325 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491326 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121327 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031328 }
1329
1330 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:001331 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
1332 items_to_check,
sorin9797aba2015-04-17 17:15:031333 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361334 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031335 const UpdateCheckCallback& update_check_callback) override {
1336 /*
1337 Fake the following response:
1338
1339 <?xml version='1.0' encoding='UTF-8'?>
1340 <response protocol='3.0'>
1341 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1342 <updatecheck status='ok'>
1343 <urls>
1344 <url codebase='http://localhost/download/'/>
1345 </urls>
1346 <manifest version='1.0' prodversionmin='11.0.1.0'>
1347 <packages>
sorin74e70672016-02-03 03:13:101348 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1349 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1350 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:031351 </packages>
1352 </manifest>
1353 </updatecheck>
1354 </app>
1355 </response>
1356 */
1357 UpdateResponse::Result::Manifest::Package package;
1358 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101359 package.hash_sha256 =
1360 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:031361 UpdateResponse::Result result;
1362 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
1363 result.crx_urls.push_back(GURL("http://localhost/download/"));
1364 result.manifest.version = "1.0";
1365 result.manifest.browser_min_version = "11.0.1.0";
1366 result.manifest.packages.push_back(package);
1367
1368 UpdateResponse::Results results;
1369 results.list.push_back(result);
1370
1371 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341372 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031373 return true;
1374 }
1375 };
1376
1377 class FakeCrxDownloader : public CrxDownloader {
1378 public:
dchengd0fc6aa92016-04-22 18:03:121379 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031380 bool is_background_download,
1381 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101382 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121383 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031384 }
1385
1386 private:
sorin74e70672016-02-03 03:13:101387 FakeCrxDownloader()
1388 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031389 ~FakeCrxDownloader() override {}
1390
1391 void DoStartDownload(const GURL& url) override {
1392 DownloadMetrics download_metrics;
1393 download_metrics.url = url;
1394 download_metrics.downloader = DownloadMetrics::kNone;
1395 download_metrics.error = 0;
1396 download_metrics.downloaded_bytes = 1843;
1397 download_metrics.total_bytes = 1843;
1398 download_metrics.download_time_ms = 1000;
1399
1400 FilePath path;
1401 EXPECT_TRUE(MakeTestFile(
1402 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1403
1404 Result result;
1405 result.error = 0;
1406 result.response = path;
1407 result.downloaded_bytes = 1843;
1408 result.total_bytes = 1843;
1409
1410 base::ThreadTaskRunnerHandle::Get()->PostTask(
1411 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1412 base::Unretained(this), result));
1413
1414 base::ThreadTaskRunnerHandle::Get()->PostTask(
1415 FROM_HERE,
1416 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1417 base::Unretained(this), true, result, download_metrics));
1418 }
1419 };
1420
1421 class FakePingManager : public FakePingManagerImpl {
1422 public:
sorin958b5d32016-01-09 02:00:201423 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031424 : FakePingManagerImpl(config) {}
1425 ~FakePingManager() override {
1426 const auto& ping_items = items();
1427 EXPECT_EQ(1U, ping_items.size());
1428 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001429 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
1430 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031431 EXPECT_EQ(3, ping_items[0].error_category); // kInstallError.
1432 EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError.
1433 }
1434 };
1435
dchengd0fc6aa92016-04-22 18:03:121436 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091437 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171438 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031439 &FakeCrxDownloader::Create));
1440
1441 MockObserver observer;
1442 {
1443 InSequence seq;
1444 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1445 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1446 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1447 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1448 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1449 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1450 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1451 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1452 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1453 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1454 }
1455
1456 update_client->AddObserver(&observer);
1457
1458 std::vector<std::string> ids;
1459 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
1460
1461 update_client->Update(
1462 ids, base::Bind(&DataCallbackFake::Callback),
sorinf9f4834d2015-04-28 17:15:021463 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031464
1465 RunThreads();
1466
1467 update_client->RemoveObserver(&observer);
1468}
1469
1470// Tests the fallback from differential to full update scenario for one CRX.
1471TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
1472 class DataCallbackFake {
1473 public:
1474 static void Callback(const std::vector<std::string>& ids,
1475 std::vector<CrxComponent>* components) {
1476 static int num_calls = 0;
1477
1478 // Must use the same stateful installer object.
1479 static scoped_refptr<CrxInstaller> installer(
1480 new VersionedTestInstaller());
1481
1482 ++num_calls;
1483
1484 CrxComponent crx;
1485 crx.name = "test_ihfo";
1486 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
1487 crx.installer = installer;
1488 if (num_calls == 1) {
pwnalldb0b72412016-08-19 21:39:121489 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031490 } else if (num_calls == 2) {
pwnalldb0b72412016-08-19 21:39:121491 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031492 } else {
1493 NOTREACHED();
1494 }
1495
1496 components->push_back(crx);
1497 }
1498 };
1499
1500 class CompletionCallbackFake {
1501 public:
sorin7b8650522016-11-02 18:23:411502 static void Callback(const base::Closure& quit_closure, Error error) {
1503 EXPECT_EQ(Error::NONE, error);
sorin9797aba2015-04-17 17:15:031504 quit_closure.Run();
1505 }
1506 };
1507
1508 class FakeUpdateChecker : public UpdateChecker {
1509 public:
dchengd0fc6aa92016-04-22 18:03:121510 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571511 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491512 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121513 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin9797aba2015-04-17 17:15:031514 }
1515
1516 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:001517 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
1518 items_to_check,
sorin9797aba2015-04-17 17:15:031519 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361520 bool enabled_component_updates,
sorin9797aba2015-04-17 17:15:031521 const UpdateCheckCallback& update_check_callback) override {
1522 static int num_call = 0;
1523 ++num_call;
1524
1525 UpdateResponse::Results results;
1526
1527 if (num_call == 1) {
1528 /*
1529 Fake the following response:
1530 <?xml version='1.0' encoding='UTF-8'?>
1531 <response protocol='3.0'>
1532 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1533 <updatecheck status='ok'>
1534 <urls>
1535 <url codebase='http://localhost/download/'/>
1536 </urls>
1537 <manifest version='1.0' prodversionmin='11.0.1.0'>
1538 <packages>
sorin74e70672016-02-03 03:13:101539 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1540 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1541 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031542 </packages>
1543 </manifest>
1544 </updatecheck>
1545 </app>
1546 </response>
1547 */
1548 UpdateResponse::Result::Manifest::Package package;
1549 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101550 package.hash_sha256 =
1551 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031552 package.fingerprint = "1";
1553 UpdateResponse::Result result;
1554 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1555 result.crx_urls.push_back(GURL("http://localhost/download/"));
1556 result.manifest.version = "1.0";
1557 result.manifest.browser_min_version = "11.0.1.0";
1558 result.manifest.packages.push_back(package);
1559 results.list.push_back(result);
1560 } else if (num_call == 2) {
1561 /*
1562 Fake the following response:
1563 <?xml version='1.0' encoding='UTF-8'?>
1564 <response protocol='3.0'>
1565 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1566 <updatecheck status='ok'>
1567 <urls>
1568 <url codebase='http://localhost/download/'/>
1569 <url codebasediff='http://localhost/download/'/>
1570 </urls>
1571 <manifest version='2.0' prodversionmin='11.0.1.0'>
1572 <packages>
1573 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1574 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101575 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1576 0ecde26c262bad942b112990'
1577 fp='22'
1578 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261579 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031580 </packages>
1581 </manifest>
1582 </updatecheck>
1583 </app>
1584 </response>
1585 */
1586 UpdateResponse::Result::Manifest::Package package;
1587 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1588 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101589 package.hash_sha256 =
1590 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1591 package.hashdiff_sha256 =
1592 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031593 package.fingerprint = "22";
1594 UpdateResponse::Result result;
1595 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1596 result.crx_urls.push_back(GURL("http://localhost/download/"));
1597 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1598 result.manifest.version = "2.0";
1599 result.manifest.browser_min_version = "11.0.1.0";
1600 result.manifest.packages.push_back(package);
1601 results.list.push_back(result);
1602 } else {
1603 NOTREACHED();
1604 }
1605
1606 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341607 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin9797aba2015-04-17 17:15:031608 return true;
1609 }
1610 };
1611
1612 class FakeCrxDownloader : public CrxDownloader {
1613 public:
dchengd0fc6aa92016-04-22 18:03:121614 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031615 bool is_background_download,
1616 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101617 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121618 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin9797aba2015-04-17 17:15:031619 }
1620
1621 private:
sorin74e70672016-02-03 03:13:101622 FakeCrxDownloader()
1623 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin9797aba2015-04-17 17:15:031624 ~FakeCrxDownloader() override {}
1625
1626 void DoStartDownload(const GURL& url) override {
1627 DownloadMetrics download_metrics;
1628 FilePath path;
1629 Result result;
1630 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1631 download_metrics.url = url;
1632 download_metrics.downloader = DownloadMetrics::kNone;
1633 download_metrics.error = 0;
1634 download_metrics.downloaded_bytes = 53638;
1635 download_metrics.total_bytes = 53638;
1636 download_metrics.download_time_ms = 2000;
1637
1638 EXPECT_TRUE(MakeTestFile(
1639 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1640
1641 result.error = 0;
1642 result.response = path;
1643 result.downloaded_bytes = 53638;
1644 result.total_bytes = 53638;
1645 } else if (url.path() ==
1646 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1647 // A download error is injected on this execution path.
1648 download_metrics.url = url;
1649 download_metrics.downloader = DownloadMetrics::kNone;
1650 download_metrics.error = -1;
1651 download_metrics.downloaded_bytes = 0;
1652 download_metrics.total_bytes = 2105;
1653 download_metrics.download_time_ms = 1000;
1654
1655 EXPECT_TRUE(MakeTestFile(
1656 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1657
1658 result.error = -1;
1659 result.response = path;
1660 result.downloaded_bytes = 0;
1661 result.total_bytes = 2105;
1662 } else if (url.path() ==
1663 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
1664 download_metrics.url = url;
1665 download_metrics.downloader = DownloadMetrics::kNone;
1666 download_metrics.error = 0;
1667 download_metrics.downloaded_bytes = 53855;
1668 download_metrics.total_bytes = 53855;
1669 download_metrics.download_time_ms = 1000;
1670
1671 EXPECT_TRUE(MakeTestFile(
1672 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
1673
1674 result.error = 0;
1675 result.response = path;
1676 result.downloaded_bytes = 53855;
1677 result.total_bytes = 53855;
1678 }
1679
1680 base::ThreadTaskRunnerHandle::Get()->PostTask(
1681 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1682 base::Unretained(this), result));
1683
1684 base::ThreadTaskRunnerHandle::Get()->PostTask(
1685 FROM_HERE,
1686 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
1687 base::Unretained(this), true, result, download_metrics));
1688 }
1689 };
1690
1691 class FakePingManager : public FakePingManagerImpl {
1692 public:
sorin958b5d32016-01-09 02:00:201693 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin9797aba2015-04-17 17:15:031694 : FakePingManagerImpl(config) {}
1695 ~FakePingManager() override {
1696 const auto& ping_items = items();
1697 EXPECT_EQ(2U, ping_items.size());
1698 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:001699 EXPECT_EQ(base::Version("0.8"), ping_items[0].previous_version);
1700 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin9797aba2015-04-17 17:15:031701 EXPECT_EQ(0, ping_items[0].error_category);
1702 EXPECT_EQ(0, ping_items[0].error_code);
1703 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
robpercivaldcd8b102016-01-25 19:39:001704 EXPECT_EQ(base::Version("1.0"), ping_items[1].previous_version);
1705 EXPECT_EQ(base::Version("2.0"), ping_items[1].next_version);
sorin9797aba2015-04-17 17:15:031706 EXPECT_TRUE(ping_items[1].diff_update_failed);
1707 EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError.
1708 EXPECT_EQ(-1, ping_items[1].diff_error_code);
1709 }
1710 };
1711
dchengd0fc6aa92016-04-22 18:03:121712 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091713 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171714 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin9797aba2015-04-17 17:15:031715 &FakeCrxDownloader::Create));
1716
1717 MockObserver observer;
1718 {
1719 InSequence seq;
1720 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1721 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1722 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1723 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1724 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1725 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1726 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1727 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1728 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1729 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1730
1731 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1732 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1733 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1734 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1735 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1736 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1737 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
1738 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1739 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1740 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1741 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1742 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1743 }
1744
1745 update_client->AddObserver(&observer);
1746
1747 std::vector<std::string> ids;
1748 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
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 {
1759 base::RunLoop runloop;
1760 update_client->Update(
1761 ids, base::Bind(&DataCallbackFake::Callback),
1762 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
1763 runloop.Run();
1764 }
1765
1766 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:091767}
1768
1769// Tests the queuing of update checks. In this scenario, two update checks are
1770// done for one CRX. The second update check call is queued up and will run
1771// after the first check has completed. The CRX has no updates.
1772TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
1773 class DataCallbackFake {
1774 public:
1775 static void Callback(const std::vector<std::string>& ids,
1776 std::vector<CrxComponent>* components) {
1777 CrxComponent crx;
1778 crx.name = "test_jebg";
1779 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121780 crx.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:091781 crx.installer = new TestInstaller;
1782 components->push_back(crx);
1783 }
1784 };
1785
1786 class CompletionCallbackFake {
1787 public:
sorin7b8650522016-11-02 18:23:411788 static void Callback(const base::Closure& quit_closure, Error error) {
sorin7c717622015-05-26 19:59:091789 static int num_call = 0;
1790 ++num_call;
1791
sorin7b8650522016-11-02 18:23:411792 EXPECT_EQ(Error::NONE, error);
sorin7c717622015-05-26 19:59:091793
1794 if (num_call == 2)
1795 quit_closure.Run();
1796 }
1797 };
1798
1799 class FakeUpdateChecker : public UpdateChecker {
1800 public:
dchengd0fc6aa92016-04-22 18:03:121801 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571802 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491803 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121804 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin7c717622015-05-26 19:59:091805 }
1806
1807 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:001808 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
1809 items_to_check,
sorin7c717622015-05-26 19:59:091810 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361811 bool enabled_component_updates,
sorin7c717622015-05-26 19:59:091812 const UpdateCheckCallback& update_check_callback) override {
1813 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:171814 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:341815 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin7c717622015-05-26 19:59:091816 return true;
1817 }
1818 };
1819
1820 class FakeCrxDownloader : public CrxDownloader {
1821 public:
dchengd0fc6aa92016-04-22 18:03:121822 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:091823 bool is_background_download,
1824 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101825 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121826 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin7c717622015-05-26 19:59:091827 }
1828
1829 private:
sorin74e70672016-02-03 03:13:101830 FakeCrxDownloader()
1831 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin7c717622015-05-26 19:59:091832 ~FakeCrxDownloader() override {}
1833
1834 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
1835 };
1836
1837 class FakePingManager : public FakePingManagerImpl {
1838 public:
sorin958b5d32016-01-09 02:00:201839 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin7c717622015-05-26 19:59:091840 : FakePingManagerImpl(config) {}
1841 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
1842 };
1843
dchengd0fc6aa92016-04-22 18:03:121844 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:091845 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:171846 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin7c717622015-05-26 19:59:091847 &FakeCrxDownloader::Create));
1848
1849 MockObserver observer;
1850 InSequence seq;
1851 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1852 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1853 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1854 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1855 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1856 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1857 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
1858 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1859
1860 update_client->AddObserver(&observer);
1861
1862 std::vector<std::string> ids;
1863 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
1864
1865 update_client->Update(
1866 ids, base::Bind(&DataCallbackFake::Callback),
1867 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
1868 update_client->Update(
1869 ids, base::Bind(&DataCallbackFake::Callback),
1870 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
1871
1872 RunThreads();
1873
1874 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:091875}
1876
1877// Tests the install of one CRX.
1878TEST_F(UpdateClientTest, OneCrxInstall) {
1879 class DataCallbackFake {
1880 public:
1881 static void Callback(const std::vector<std::string>& ids,
1882 std::vector<CrxComponent>* components) {
1883 CrxComponent crx;
1884 crx.name = "test_jebg";
1885 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:121886 crx.version = base::Version("0.0");
sorin7c717622015-05-26 19:59:091887 crx.installer = new TestInstaller;
1888
1889 components->push_back(crx);
1890 }
1891 };
1892
1893 class CompletionCallbackFake {
1894 public:
sorin7b8650522016-11-02 18:23:411895 static void Callback(const base::Closure& quit_closure, Error error) {
1896 EXPECT_EQ(Error::NONE, error);
sorin7c717622015-05-26 19:59:091897 quit_closure.Run();
1898 }
1899 };
1900
1901 class FakeUpdateChecker : public UpdateChecker {
1902 public:
dchengd0fc6aa92016-04-22 18:03:121903 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:571904 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:491905 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:121906 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin7c717622015-05-26 19:59:091907 }
1908
1909 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:001910 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
1911 items_to_check,
sorin7c717622015-05-26 19:59:091912 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:361913 bool enabled_component_updates,
sorin7c717622015-05-26 19:59:091914 const UpdateCheckCallback& update_check_callback) override {
1915 /*
1916 Fake the following response:
1917
1918 <?xml version='1.0' encoding='UTF-8'?>
1919 <response protocol='3.0'>
1920 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1921 <updatecheck status='ok'>
1922 <urls>
1923 <url codebase='http://localhost/download/'/>
1924 </urls>
1925 <manifest version='1.0' prodversionmin='11.0.1.0'>
1926 <packages>
sorin74e70672016-02-03 03:13:101927 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1928 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1929 7c9b12cb7cc067667bde87'/>
sorin7c717622015-05-26 19:59:091930 </packages>
1931 </manifest>
1932 </updatecheck>
1933 </app>
1934 </response>
1935 */
1936 UpdateResponse::Result::Manifest::Package package;
1937 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101938 package.hash_sha256 =
1939 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin7c717622015-05-26 19:59:091940 UpdateResponse::Result result;
1941 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
1942 result.crx_urls.push_back(GURL("http://localhost/download/"));
1943 result.manifest.version = "1.0";
1944 result.manifest.browser_min_version = "11.0.1.0";
1945 result.manifest.packages.push_back(package);
1946
1947 UpdateResponse::Results results;
1948 results.list.push_back(result);
1949
1950 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorinfccbf2d2016-04-04 20:34:341951 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
sorin7c717622015-05-26 19:59:091952 return true;
1953 }
1954 };
1955
1956 class FakeCrxDownloader : public CrxDownloader {
1957 public:
dchengd0fc6aa92016-04-22 18:03:121958 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:091959 bool is_background_download,
1960 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:101961 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:121962 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin7c717622015-05-26 19:59:091963 }
1964
1965 private:
sorin74e70672016-02-03 03:13:101966 FakeCrxDownloader()
1967 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin7c717622015-05-26 19:59:091968 ~FakeCrxDownloader() override {}
1969
1970 void DoStartDownload(const GURL& url) override {
1971 DownloadMetrics download_metrics;
1972 FilePath path;
1973 Result result;
1974 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
1975 download_metrics.url = url;
1976 download_metrics.downloader = DownloadMetrics::kNone;
1977 download_metrics.error = 0;
1978 download_metrics.downloaded_bytes = 1843;
1979 download_metrics.total_bytes = 1843;
1980 download_metrics.download_time_ms = 1000;
1981
1982 EXPECT_TRUE(MakeTestFile(
1983 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1984
1985 result.error = 0;
1986 result.response = path;
1987 result.downloaded_bytes = 1843;
1988 result.total_bytes = 1843;
1989 } else {
1990 NOTREACHED();
1991 }
1992
1993 base::ThreadTaskRunnerHandle::Get()->PostTask(
1994 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
1995 base::Unretained(this), result));
1996
1997 base::ThreadTaskRunnerHandle::Get()->PostTask(
1998 FROM_HERE,
1999 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
2000 base::Unretained(this), true, result, download_metrics));
2001 }
2002 };
2003
2004 class FakePingManager : public FakePingManagerImpl {
2005 public:
sorin958b5d32016-01-09 02:00:202006 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin7c717622015-05-26 19:59:092007 : FakePingManagerImpl(config) {}
2008 ~FakePingManager() override {
2009 const auto& ping_items = items();
2010 EXPECT_EQ(1U, ping_items.size());
2011 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:002012 EXPECT_EQ(base::Version("0.0"), ping_items[0].previous_version);
2013 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
sorin7c717622015-05-26 19:59:092014 EXPECT_EQ(0, ping_items[0].error_category);
2015 EXPECT_EQ(0, ping_items[0].error_code);
2016 }
2017 };
2018
dchengd0fc6aa92016-04-22 18:03:122019 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin7c717622015-05-26 19:59:092020 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:172021 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin7c717622015-05-26 19:59:092022 &FakeCrxDownloader::Create));
2023
2024 // Verify that calling Install sets ondemand.
2025 OnDemandTester ondemand_tester(update_client, true);
2026
2027 MockObserver observer;
2028 ON_CALL(observer, OnEvent(_, _))
2029 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
2030
2031 InSequence seq;
2032 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2033 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2034 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2035 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2036 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
2037 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2038 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2039 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2040 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2041 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2042
2043 update_client->AddObserver(&observer);
2044
2045 update_client->Install(
2046 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2047 base::Bind(&DataCallbackFake::Callback),
2048 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2049
2050 RunThreads();
2051
2052 update_client->RemoveObserver(&observer);
sorin9797aba2015-04-17 17:15:032053}
2054
sorin08d153c2015-10-30 00:04:202055// Tests that overlapping installs of the same CRX result in an error.
2056TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
2057 class DataCallbackFake {
2058 public:
2059 static void Callback(const std::vector<std::string>& ids,
2060 std::vector<CrxComponent>* components) {
2061 CrxComponent crx;
2062 crx.name = "test_jebg";
2063 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122064 crx.version = base::Version("0.0");
sorin08d153c2015-10-30 00:04:202065 crx.installer = new TestInstaller;
2066
2067 components->push_back(crx);
2068 }
2069 };
2070
2071 class CompletionCallbackFake {
2072 public:
sorin7b8650522016-11-02 18:23:412073 static void Callback(const base::Closure& quit_closure, Error error) {
sorin08d153c2015-10-30 00:04:202074 static int num_call = 0;
2075 ++num_call;
2076
2077 EXPECT_LE(num_call, 2);
2078
2079 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412080 EXPECT_EQ(Error::UPDATE_IN_PROGRESS, error);
sorin08d153c2015-10-30 00:04:202081 return;
2082 }
2083 if (num_call == 2) {
sorin7b8650522016-11-02 18:23:412084 EXPECT_EQ(Error::NONE, error);
sorin08d153c2015-10-30 00:04:202085 quit_closure.Run();
2086 }
2087 }
2088 };
2089
2090 class FakeUpdateChecker : public UpdateChecker {
2091 public:
dchengd0fc6aa92016-04-22 18:03:122092 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572093 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492094 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122095 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorin08d153c2015-10-30 00:04:202096 }
2097
2098 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:002099 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
2100 items_to_check,
sorin08d153c2015-10-30 00:04:202101 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362102 bool enabled_component_updates,
sorin08d153c2015-10-30 00:04:202103 const UpdateCheckCallback& update_check_callback) override {
2104 base::ThreadTaskRunnerHandle::Get()->PostTask(
sorin1bc5eff2016-02-17 18:45:172105 FROM_HERE,
sorinfccbf2d2016-04-04 20:34:342106 base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
sorin08d153c2015-10-30 00:04:202107 return true;
2108 }
2109 };
2110
2111 class FakeCrxDownloader : public CrxDownloader {
2112 public:
dchengd0fc6aa92016-04-22 18:03:122113 static std::unique_ptr<CrxDownloader> Create(
sorin08d153c2015-10-30 00:04:202114 bool is_background_download,
2115 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102116 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122117 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorin08d153c2015-10-30 00:04:202118 }
2119
2120 private:
sorin74e70672016-02-03 03:13:102121 FakeCrxDownloader()
2122 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin08d153c2015-10-30 00:04:202123 ~FakeCrxDownloader() override {}
2124
2125 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2126 };
2127
2128 class FakePingManager : public FakePingManagerImpl {
2129 public:
sorin958b5d32016-01-09 02:00:202130 explicit FakePingManager(const scoped_refptr<Configurator>& config)
sorin08d153c2015-10-30 00:04:202131 : FakePingManagerImpl(config) {}
2132 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
2133 };
2134
dchengd0fc6aa92016-04-22 18:03:122135 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
sorin08d153c2015-10-30 00:04:202136 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dcheng51ace48a2015-12-26 22:45:172137 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
sorin08d153c2015-10-30 00:04:202138 &FakeCrxDownloader::Create));
2139
2140 // Verify that calling Install sets ondemand.
2141 OnDemandTester ondemand_tester(update_client, true);
2142
2143 MockObserver observer;
2144 ON_CALL(observer, OnEvent(_, _))
2145 .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
2146
2147 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2148 "jebgalgnebhfojomionfpkfelancnnkf"))
2149 .Times(1);
2150 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2151 "jebgalgnebhfojomionfpkfelancnnkf"))
2152 .Times(1);
2153
2154 update_client->AddObserver(&observer);
2155
2156 update_client->Install(
2157 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2158 base::Bind(&DataCallbackFake::Callback),
2159 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2160
2161 update_client->Install(
2162 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2163 base::Bind(&DataCallbackFake::Callback),
2164 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2165
2166 RunThreads();
2167
2168 update_client->RemoveObserver(&observer);
sorin08d153c2015-10-30 00:04:202169}
2170
asargente90363b2015-09-09 22:40:072171// Make sure that we don't get any crashes when trying to update an empty list
2172// of ids.
2173TEST_F(UpdateClientTest, EmptyIdList) {
2174 class DataCallbackFake {
2175 public:
2176 static void Callback(const std::vector<std::string>& ids,
2177 std::vector<CrxComponent>* components) {}
2178 };
2179
2180 class CompletionCallbackFake {
2181 public:
sorin7b8650522016-11-02 18:23:412182 static void Callback(const base::Closure& quit_closure, Error error) {
asargente90363b2015-09-09 22:40:072183 quit_closure.Run();
2184 }
2185 };
2186 class FakeUpdateChecker : public UpdateChecker {
2187 public:
dchengd0fc6aa92016-04-22 18:03:122188 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572189 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492190 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122191 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
asargente90363b2015-09-09 22:40:072192 }
2193
2194 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:002195 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
2196 items_to_check,
asargente90363b2015-09-09 22:40:072197 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362198 bool enabled_component_updates,
asargente90363b2015-09-09 22:40:072199 const UpdateCheckCallback& update_check_callback) override {
2200 return false;
2201 }
2202 };
2203
2204 class FakeCrxDownloader : public CrxDownloader {
2205 public:
dchengd0fc6aa92016-04-22 18:03:122206 static std::unique_ptr<CrxDownloader> Create(
asargente90363b2015-09-09 22:40:072207 bool is_background_download,
2208 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102209 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122210 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
asargente90363b2015-09-09 22:40:072211 }
2212
2213 private:
sorin74e70672016-02-03 03:13:102214 FakeCrxDownloader()
2215 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
asargente90363b2015-09-09 22:40:072216 ~FakeCrxDownloader() override {}
2217
2218 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2219 };
2220
2221 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
dchengd0fc6aa92016-04-22 18:03:122222 config(), base::WrapUnique(new FakePingManagerImpl(config())),
asargente90363b2015-09-09 22:40:072223 &FakeUpdateChecker::Create, &FakeCrxDownloader::Create));
2224
2225 std::vector<std::string> empty_id_list;
2226 base::RunLoop runloop;
2227 update_client->Update(
2228 empty_id_list, base::Bind(&DataCallbackFake::Callback),
2229 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2230 runloop.Run();
asargente90363b2015-09-09 22:40:072231}
2232
sorin805aa03112016-01-14 23:01:312233TEST_F(UpdateClientTest, SendUninstallPing) {
2234 class FakeUpdateChecker : public UpdateChecker {
2235 public:
dchengd0fc6aa92016-04-22 18:03:122236 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572237 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492238 PersistedData* metadata) {
sorin805aa03112016-01-14 23:01:312239 return nullptr;
2240 }
2241
2242 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:002243 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
2244 items_to_check,
sorin805aa03112016-01-14 23:01:312245 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362246 bool enabled_component_updates,
sorin805aa03112016-01-14 23:01:312247 const UpdateCheckCallback& update_check_callback) override {
2248 return false;
2249 }
2250 };
2251
2252 class FakeCrxDownloader : public CrxDownloader {
2253 public:
dchengd0fc6aa92016-04-22 18:03:122254 static std::unique_ptr<CrxDownloader> Create(
sorin805aa03112016-01-14 23:01:312255 bool is_background_download,
2256 net::URLRequestContextGetter* context_getter,
sorin74e70672016-02-03 03:13:102257 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
sorin805aa03112016-01-14 23:01:312258 return nullptr;
2259 }
2260
2261 private:
sorin74e70672016-02-03 03:13:102262 FakeCrxDownloader()
2263 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
sorin805aa03112016-01-14 23:01:312264 ~FakeCrxDownloader() override {}
2265
2266 void DoStartDownload(const GURL& url) override {}
2267 };
2268
2269 class FakePingManager : public FakePingManagerImpl {
2270 public:
2271 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2272 : FakePingManagerImpl(config) {}
2273 ~FakePingManager() override {
2274 const auto& ping_items = items();
2275 EXPECT_EQ(1U, ping_items.size());
2276 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
robpercivaldcd8b102016-01-25 19:39:002277 EXPECT_EQ(base::Version("1.0"), ping_items[0].previous_version);
2278 EXPECT_EQ(base::Version("0.0"), ping_items[0].next_version);
sorin805aa03112016-01-14 23:01:312279 EXPECT_EQ(10, ping_items[0].extra_code1);
2280 }
2281 };
2282
dchengd0fc6aa92016-04-22 18:03:122283 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorin805aa03112016-01-14 23:01:312284 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2285 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2286 &FakeCrxDownloader::Create));
2287
2288 update_client->SendUninstallPing("jebgalgnebhfojomionfpkfelancnnkf",
2289 base::Version("1.0"), 10);
2290}
2291
sorinfccbf2d2016-04-04 20:34:342292TEST_F(UpdateClientTest, RetryAfter) {
2293 class DataCallbackFake {
2294 public:
2295 static void Callback(const std::vector<std::string>& ids,
2296 std::vector<CrxComponent>* components) {
2297 CrxComponent crx;
2298 crx.name = "test_jebg";
2299 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122300 crx.version = base::Version("0.9");
sorinfccbf2d2016-04-04 20:34:342301 crx.installer = new TestInstaller;
2302 components->push_back(crx);
2303 }
2304 };
2305
2306 class CompletionCallbackFake {
2307 public:
sorin7b8650522016-11-02 18:23:412308 static void Callback(const base::Closure& quit_closure, Error error) {
sorinfccbf2d2016-04-04 20:34:342309 static int num_call = 0;
2310 ++num_call;
2311
2312 EXPECT_LE(num_call, 4);
2313
2314 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412315 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342316 } else if (num_call == 2) {
2317 // This request is throttled since the update engine received a
2318 // positive |retry_after_sec| value in the update check response.
sorin7b8650522016-11-02 18:23:412319 EXPECT_EQ(Error::RETRY_LATER, error);
sorinfccbf2d2016-04-04 20:34:342320 } else if (num_call == 3) {
2321 // This request is a foreground Install, which is never throttled.
2322 // The update engine received a |retry_after_sec| value of 0, which
2323 // resets the throttling.
sorin7b8650522016-11-02 18:23:412324 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342325 } else if (num_call == 4) {
2326 // This request succeeds since there is no throttling in effect.
sorin7b8650522016-11-02 18:23:412327 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342328 }
2329
2330 quit_closure.Run();
2331 }
2332 };
2333
2334 class FakeUpdateChecker : public UpdateChecker {
2335 public:
dchengd0fc6aa92016-04-22 18:03:122336 static std::unique_ptr<UpdateChecker> Create(
wafflesd2d9a332016-04-09 01:59:572337 const scoped_refptr<Configurator>& config,
wafflese7dff732016-04-15 23:51:492338 PersistedData* metadata) {
dchengd0fc6aa92016-04-22 18:03:122339 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
sorinfccbf2d2016-04-04 20:34:342340 }
2341
2342 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:002343 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
2344 items_to_check,
sorinfccbf2d2016-04-04 20:34:342345 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362346 bool enabled_component_updates,
sorinfccbf2d2016-04-04 20:34:342347 const UpdateCheckCallback& update_check_callback) override {
2348 static int num_call = 0;
2349 ++num_call;
2350
2351 EXPECT_LE(num_call, 3);
2352
2353 int retry_after_sec(0);
2354 if (num_call == 1) {
2355 // Throttle the next call.
2356 retry_after_sec = 60 * 60; // 1 hour.
2357 }
2358
2359 base::ThreadTaskRunnerHandle::Get()->PostTask(
2360 FROM_HERE, base::Bind(update_check_callback, 0,
2361 UpdateResponse::Results(), retry_after_sec));
2362 return true;
2363 }
2364 };
2365
2366 class FakeCrxDownloader : public CrxDownloader {
2367 public:
dchengd0fc6aa92016-04-22 18:03:122368 static std::unique_ptr<CrxDownloader> Create(
sorinfccbf2d2016-04-04 20:34:342369 bool is_background_download,
2370 net::URLRequestContextGetter* context_getter,
2371 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:122372 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
sorinfccbf2d2016-04-04 20:34:342373 }
2374
2375 private:
2376 FakeCrxDownloader()
2377 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
2378 ~FakeCrxDownloader() override {}
2379
2380 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2381 };
2382
2383 class FakePingManager : public FakePingManagerImpl {
2384 public:
2385 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2386 : FakePingManagerImpl(config) {}
2387 ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
2388 };
2389
dchengd0fc6aa92016-04-22 18:03:122390 std::unique_ptr<PingManager> ping_manager(new FakePingManager(config()));
sorinfccbf2d2016-04-04 20:34:342391 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2392 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2393 &FakeCrxDownloader::Create));
2394
2395 MockObserver observer;
2396
2397 InSequence seq;
2398 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2399 "jebgalgnebhfojomionfpkfelancnnkf"))
2400 .Times(1);
2401 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2402 "jebgalgnebhfojomionfpkfelancnnkf"))
2403 .Times(1);
2404 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2405 "jebgalgnebhfojomionfpkfelancnnkf"))
2406 .Times(1);
2407 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2408 "jebgalgnebhfojomionfpkfelancnnkf"))
2409 .Times(1);
2410 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2411 "jebgalgnebhfojomionfpkfelancnnkf"))
2412 .Times(1);
2413 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2414 "jebgalgnebhfojomionfpkfelancnnkf"))
2415 .Times(1);
2416
2417 update_client->AddObserver(&observer);
2418
2419 std::vector<std::string> ids;
2420 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
2421
2422 {
2423 // The engine handles this Update call but responds with a valid
2424 // |retry_after_sec|, which causes subsequent calls to fail.
2425 base::RunLoop runloop;
2426 update_client->Update(
2427 ids, base::Bind(&DataCallbackFake::Callback),
2428 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2429 runloop.Run();
2430 }
2431
2432 {
2433 // This call will result in a completion callback invoked with
2434 // Error::ERROR_UPDATE_RETRY_LATER.
2435 base::RunLoop runloop;
2436 update_client->Update(
2437 ids, base::Bind(&DataCallbackFake::Callback),
2438 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2439 runloop.Run();
2440 }
2441
2442 {
2443 // The Install call is handled, and the throttling is reset due to
2444 // the value of |retry_after_sec| in the completion callback.
2445 base::RunLoop runloop;
2446 update_client->Install(
2447 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2448 base::Bind(&DataCallbackFake::Callback),
2449 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2450 runloop.Run();
2451 }
2452
2453 {
2454 // This call succeeds.
2455 base::RunLoop runloop;
2456 update_client->Update(
2457 ids, base::Bind(&DataCallbackFake::Callback),
2458 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
2459 runloop.Run();
2460 }
2461
2462 update_client->RemoveObserver(&observer);
2463}
2464
sorine84ff702016-08-04 01:22:022465// Tests the update check for two CRXs scenario. The first component supports
2466// the group policy to enable updates, and has its updates disabled. The second
2467// component has an update. The server does not honor the "updatedisabled"
2468// attribute and returns updates for both components.
2469TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
2470 class DataCallbackFake {
2471 public:
2472 static void Callback(const std::vector<std::string>& ids,
2473 std::vector<CrxComponent>* components) {
2474 CrxComponent crx1;
2475 crx1.name = "test_jebg";
2476 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnalldb0b72412016-08-19 21:39:122477 crx1.version = base::Version("0.9");
sorine84ff702016-08-04 01:22:022478 crx1.installer = new TestInstaller;
2479 crx1.supports_group_policy_enable_component_updates = true;
2480
2481 CrxComponent crx2;
2482 crx2.name = "test_ihfo";
2483 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
pwnalldb0b72412016-08-19 21:39:122484 crx2.version = base::Version("0.8");
sorine84ff702016-08-04 01:22:022485 crx2.installer = new TestInstaller;
2486
2487 components->push_back(crx1);
2488 components->push_back(crx2);
2489 }
2490 };
2491
2492 class CompletionCallbackFake {
2493 public:
sorin7b8650522016-11-02 18:23:412494 static void Callback(const base::Closure& quit_closure, Error error) {
2495 EXPECT_EQ(Error::NONE, error);
sorine84ff702016-08-04 01:22:022496 quit_closure.Run();
2497 }
2498 };
2499
2500 class FakeUpdateChecker : public UpdateChecker {
2501 public:
2502 static std::unique_ptr<UpdateChecker> Create(
2503 const scoped_refptr<Configurator>& config,
2504 PersistedData* metadata) {
2505 return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
2506 }
2507
2508 bool CheckForUpdates(
avi216d77b2016-10-31 19:36:002509 const std::map<std::string, std::unique_ptr<CrxUpdateItem>>&
2510 items_to_check,
sorine84ff702016-08-04 01:22:022511 const std::string& additional_attributes,
sorin590921d2016-08-11 23:48:362512 bool enabled_component_updates,
sorine84ff702016-08-04 01:22:022513 const UpdateCheckCallback& update_check_callback) override {
2514 /*
2515 Fake the following response:
2516
2517 <?xml version='1.0' encoding='UTF-8'?>
2518 <response protocol='3.0'>
2519 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2520 <updatecheck status='ok'>
2521 <urls>
2522 <url codebase='http://localhost/download/'/>
2523 </urls>
2524 <manifest version='1.0' prodversionmin='11.0.1.0'>
2525 <packages>
2526 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
2527 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
2528 7c9b12cb7cc067667bde87'/>
2529 </packages>
2530 </manifest>
2531 </updatecheck>
2532 </app>
2533 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
2534 <updatecheck status='ok'>
2535 <urls>
2536 <url codebase='http://localhost/download/'/>
2537 </urls>
2538 <manifest version='1.0' prodversionmin='11.0.1.0'>
2539 <packages>
2540 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
2541 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
2542 309f156ea6d27229c0b3f9'/>
2543 </packages>
2544 </manifest>
2545 </updatecheck>
2546 </app>
2547 </response>
2548 */
sorin590921d2016-08-11 23:48:362549
2550 // UpdateClient reads the state of |enabled_component_updates| from the
2551 // configurator instance, persists its value in the corresponding
2552 // update context, and propagates it down to each of the update actions,
2553 // and further down to the UpdateChecker instance.
2554 EXPECT_FALSE(enabled_component_updates);
2555
sorine84ff702016-08-04 01:22:022556 UpdateResponse::Result::Manifest::Package package1;
2557 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
2558 package1.hash_sha256 =
2559 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
2560
2561 UpdateResponse::Result result1;
2562 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
2563 result1.crx_urls.push_back(GURL("http://localhost/download/"));
2564 result1.manifest.version = "1.0";
2565 result1.manifest.browser_min_version = "11.0.1.0";
2566 result1.manifest.packages.push_back(package1);
2567
2568 UpdateResponse::Result::Manifest::Package package2;
2569 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
2570 package2.hash_sha256 =
2571 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
2572
2573 UpdateResponse::Result result2;
2574 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
2575 result2.crx_urls.push_back(GURL("http://localhost/download/"));
2576 result2.manifest.version = "1.0";
2577 result2.manifest.browser_min_version = "11.0.1.0";
2578 result2.manifest.packages.push_back(package2);
2579
2580 UpdateResponse::Results results;
2581 results.list.push_back(result1);
2582 results.list.push_back(result2);
2583
2584 base::ThreadTaskRunnerHandle::Get()->PostTask(
2585 FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
2586 return true;
2587 }
2588 };
2589
2590 class FakeCrxDownloader : public CrxDownloader {
2591 public:
2592 static std::unique_ptr<CrxDownloader> Create(
2593 bool is_background_download,
2594 net::URLRequestContextGetter* context_getter,
2595 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
2596 return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
2597 }
2598
2599 private:
2600 FakeCrxDownloader()
2601 : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
2602 ~FakeCrxDownloader() override {}
2603
2604 void DoStartDownload(const GURL& url) override {
2605 DownloadMetrics download_metrics;
2606 FilePath path;
2607 Result result;
2608 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
2609 download_metrics.url = url;
2610 download_metrics.downloader = DownloadMetrics::kNone;
2611 download_metrics.error = 0;
2612 download_metrics.downloaded_bytes = 53638;
2613 download_metrics.total_bytes = 53638;
2614 download_metrics.download_time_ms = 2000;
2615
2616 EXPECT_TRUE(MakeTestFile(
2617 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
2618
2619 result.error = 0;
2620 result.response = path;
2621 result.downloaded_bytes = 53638;
2622 result.total_bytes = 53638;
2623 } else {
2624 NOTREACHED();
2625 }
2626
2627 base::ThreadTaskRunnerHandle::Get()->PostTask(
2628 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
2629 base::Unretained(this), result));
2630
2631 base::ThreadTaskRunnerHandle::Get()->PostTask(
2632 FROM_HERE,
2633 base::Bind(&FakeCrxDownloader::OnDownloadComplete,
2634 base::Unretained(this), true, result, download_metrics));
2635 }
2636 };
2637
2638 class FakePingManager : public FakePingManagerImpl {
2639 public:
2640 explicit FakePingManager(const scoped_refptr<Configurator>& config)
2641 : FakePingManagerImpl(config) {}
2642 ~FakePingManager() override {
2643 const auto& ping_items = items();
2644 EXPECT_EQ(2U, ping_items.size());
2645 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
2646 EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
2647 EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
2648 EXPECT_EQ(4, ping_items[0].error_category);
2649 EXPECT_EQ(2, ping_items[0].error_code);
2650 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
2651 EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
2652 EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
2653 EXPECT_EQ(0, ping_items[1].error_category);
2654 EXPECT_EQ(0, ping_items[1].error_code);
2655 }
2656 };
2657
2658 // Disables updates for the components declaring support for the group policy.
2659 config()->SetEnabledComponentUpdates(false);
2660 std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
2661 scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
2662 config(), std::move(ping_manager), &FakeUpdateChecker::Create,
2663 &FakeCrxDownloader::Create));
2664
2665 MockObserver observer;
2666 {
2667 InSequence seq;
2668 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2669 "jebgalgnebhfojomionfpkfelancnnkf"))
2670 .Times(1);
2671 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2672 "jebgalgnebhfojomionfpkfelancnnkf"))
2673 .Times(1);
2674 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2675 "jebgalgnebhfojomionfpkfelancnnkf"))
2676 .Times(1);
2677 }
2678 {
2679 InSequence seq;
2680 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2681 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2682 .Times(1);
2683 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2684 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2685 .Times(1);
2686 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
2687 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2688 .Times(1);
2689 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
2690 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2691 .Times(1);
2692 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2693 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2694 .Times(1);
2695 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2696 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2697 .Times(1);
2698 }
2699
2700 update_client->AddObserver(&observer);
2701
2702 std::vector<std::string> ids;
2703 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
2704 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
2705
2706 update_client->Update(
2707 ids, base::Bind(&DataCallbackFake::Callback),
2708 base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
2709
2710 RunThreads();
2711
2712 update_client->RemoveObserver(&observer);
2713}
2714
sorin9797aba2015-04-17 17:15:032715} // namespace update_client