blob: d5c3529050402434a77a96b62debd7f017b8a4e7 [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"
sorin9797aba2015-04-17 17:15:039#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/location.h"
avi5dd91f82015-12-25 22:30:4612#include "base/macros.h"
sorin9797aba2015-04-17 17:15:0313#include "base/memory/ref_counted.h"
sorin9797aba2015-04-17 17:15:0314#include "base/path_service.h"
15#include "base/run_loop.h"
Sorin Jianucb4431a2018-04-30 20:59:2416#include "base/stl_util.h"
fdoray03349c12017-05-17 18:06:5117#include "base/task_scheduler/post_task.h"
Sorin Jianuf40ab4b32017-10-06 22:53:4118#include "base/task_scheduler/task_traits.h"
Sorin Jianu4ab7c292017-06-15 18:40:2119#include "base/test/scoped_path_override.h"
fdoray03349c12017-05-17 18:06:5120#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0121#include "base/threading/thread_task_runner_handle.h"
sorin9797aba2015-04-17 17:15:0322#include "base/values.h"
23#include "base/version.h"
Sorin Jianu188907072018-01-22 18:42:2224#include "build/build_config.h"
wafflesd2d9a332016-04-09 01:59:5725#include "components/prefs/testing_pref_service.h"
Sorin Jianu4ab7c292017-06-15 18:40:2126#include "components/update_client/component_unpacker.h"
sorin9797aba2015-04-17 17:15:0327#include "components/update_client/crx_update_item.h"
wafflesd2d9a332016-04-09 01:59:5728#include "components/update_client/persisted_data.h"
sorin9797aba2015-04-17 17:15:0329#include "components/update_client/ping_manager.h"
sorin7cff6e52017-05-17 16:37:2330#include "components/update_client/protocol_parser.h"
sorinb120440b2015-04-27 16:34:1531#include "components/update_client/test_configurator.h"
32#include "components/update_client/test_installer.h"
sorin9797aba2015-04-17 17:15:0333#include "components/update_client/update_checker.h"
sorin7b8650522016-11-02 18:23:4134#include "components/update_client/update_client_errors.h"
sorin9797aba2015-04-17 17:15:0335#include "components/update_client/update_client_internal.h"
sorin9797aba2015-04-17 17:15:0336#include "testing/gmock/include/gmock/gmock.h"
37#include "testing/gtest/include/gtest/gtest.h"
38#include "url/gurl.h"
39
40namespace update_client {
41
42namespace {
43
44using base::FilePath;
45
46// Makes a copy of the file specified by |from_path| in a temporary directory
47// and returns the path of the copy. Returns true if successful. Cleans up if
48// there was an error creating the copy.
49bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
50 FilePath temp_dir;
51 bool result =
52 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir);
53 if (!result)
54 return false;
55
56 FilePath temp_file;
57 result = CreateTemporaryFileInDir(temp_dir, &temp_file);
58 if (!result)
59 return false;
60
61 result = CopyFile(from_path, temp_file);
62 if (!result) {
63 DeleteFile(temp_file, false);
64 return false;
65 }
66
67 *to_path = temp_file;
68 return true;
69}
70
71using Events = UpdateClient::Observer::Events;
72
73class MockObserver : public UpdateClient::Observer {
74 public:
75 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
76};
77
sorin30474f02017-04-27 00:45:4878} // namespace
sorin7c717622015-05-26 19:59:0979
sorin30474f02017-04-27 00:45:4880using ::testing::_;
81using ::testing::AtLeast;
82using ::testing::AnyNumber;
83using ::testing::DoAll;
84using ::testing::InSequence;
85using ::testing::Invoke;
86using ::testing::Mock;
87using ::testing::Return;
sorin7c717622015-05-26 19:59:0988
sorin30474f02017-04-27 00:45:4889using std::string;
sorin7c717622015-05-26 19:59:0990
Sorin Jianua8926bf2018-03-09 21:02:5391class MockPingManagerImpl : public PingManager {
sorin9797aba2015-04-17 17:15:0392 public:
sorin30474f02017-04-27 00:45:4893 struct PingData {
94 std::string id;
95 base::Version previous_version;
96 base::Version next_version;
97 int error_category = 0;
98 int error_code = 0;
99 int extra_code1 = 0;
100 int diff_error_category = 0;
101 int diff_error_code = 0;
102 bool diff_update_failed = false;
103 };
104
Sorin Jianua8926bf2018-03-09 21:02:53105 explicit MockPingManagerImpl(scoped_refptr<Configurator> config);
sorin9797aba2015-04-17 17:15:03106
Sorin Jianu560d5022018-02-12 23:11:54107 void SendPing(const Component& component, Callback callback) override;
sorin9797aba2015-04-17 17:15:03108
sorin30474f02017-04-27 00:45:48109 const std::vector<PingData>& ping_data() const;
sorin9797aba2015-04-17 17:15:03110
Sorin Jianu4ab7c292017-06-15 18:40:21111 const std::vector<std::string>& events() const;
112
Sorin Jianu560d5022018-02-12 23:11:54113 protected:
Sorin Jianua8926bf2018-03-09 21:02:53114 ~MockPingManagerImpl() override;
Sorin Jianu560d5022018-02-12 23:11:54115
sorin9797aba2015-04-17 17:15:03116 private:
sorin30474f02017-04-27 00:45:48117 std::vector<PingData> ping_data_;
Sorin Jianu4ab7c292017-06-15 18:40:21118 std::vector<std::string> events_;
Sorin Jianua8926bf2018-03-09 21:02:53119 DISALLOW_COPY_AND_ASSIGN(MockPingManagerImpl);
sorin9797aba2015-04-17 17:15:03120};
121
Sorin Jianua8926bf2018-03-09 21:02:53122MockPingManagerImpl::MockPingManagerImpl(scoped_refptr<Configurator> config)
sorin958b5d32016-01-09 02:00:20123 : PingManager(config) {}
sorin9797aba2015-04-17 17:15:03124
Sorin Jianua8926bf2018-03-09 21:02:53125MockPingManagerImpl::~MockPingManagerImpl() {}
sorin9797aba2015-04-17 17:15:03126
Sorin Jianua8926bf2018-03-09 21:02:53127void MockPingManagerImpl::SendPing(const Component& component,
Sorin Jianu560d5022018-02-12 23:11:54128 Callback callback) {
sorin30474f02017-04-27 00:45:48129 PingData ping_data;
130 ping_data.id = component.id_;
131 ping_data.previous_version = component.previous_version_;
132 ping_data.next_version = component.next_version_;
133 ping_data.error_category = component.error_category_;
134 ping_data.error_code = component.error_code_;
135 ping_data.extra_code1 = component.extra_code1_;
136 ping_data.diff_error_category = component.diff_error_category_;
137 ping_data.diff_error_code = component.diff_error_code_;
138 ping_data.diff_update_failed = component.diff_update_failed();
139 ping_data_.push_back(ping_data);
Sorin Jianu4ab7c292017-06-15 18:40:21140
141 const auto& events = component.events();
142 events_.insert(events_.end(), events.begin(), events.end());
143
Sorin Jianu560d5022018-02-12 23:11:54144 std::move(callback).Run(0, "");
sorin9797aba2015-04-17 17:15:03145}
146
Sorin Jianua8926bf2018-03-09 21:02:53147const std::vector<MockPingManagerImpl::PingData>&
148MockPingManagerImpl::ping_data() const {
sorin30474f02017-04-27 00:45:48149 return ping_data_;
sorin9797aba2015-04-17 17:15:03150}
151
Sorin Jianua8926bf2018-03-09 21:02:53152const std::vector<std::string>& MockPingManagerImpl::events() const {
Sorin Jianu4ab7c292017-06-15 18:40:21153 return events_;
154}
155
sorin9797aba2015-04-17 17:15:03156class UpdateClientTest : public testing::Test {
157 public:
158 UpdateClientTest();
159 ~UpdateClientTest() override;
160
sorin9797aba2015-04-17 17:15:03161 protected:
162 void RunThreads();
163
164 // Returns the full path to a test file.
165 static base::FilePath TestFilePath(const char* file);
166
sorine84ff702016-08-04 01:22:02167 scoped_refptr<update_client::TestConfigurator> config() { return config_; }
wafflese7dff732016-04-15 23:51:49168 update_client::PersistedData* metadata() { return metadata_.get(); }
sorin9797aba2015-04-17 17:15:03169
Sorin Jianua8ef73d2017-11-02 16:55:17170 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
sorinf9f4834d2015-04-28 17:15:02171
172 private:
sorin30474f02017-04-27 00:45:48173 static constexpr int kNumWorkerThreads_ = 2;
sorinf9f4834d2015-04-28 17:15:02174
fdoray03349c12017-05-17 18:06:51175 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin9797aba2015-04-17 17:15:03176 base::RunLoop runloop_;
sorin9797aba2015-04-17 17:15:03177
Sorin Jianucc048f892017-07-26 02:05:54178 scoped_refptr<update_client::TestConfigurator> config_ =
179 base::MakeRefCounted<TestConfigurator>();
180 std::unique_ptr<TestingPrefServiceSimple> pref_ =
Jinho Bangda4e4282018-01-03 13:21:23181 std::make_unique<TestingPrefServiceSimple>();
wafflesd2d9a332016-04-09 01:59:57182 std::unique_ptr<update_client::PersistedData> metadata_;
sorinf9f4834d2015-04-28 17:15:02183
sorin9797aba2015-04-17 17:15:03184 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
185};
186
sorin30474f02017-04-27 00:45:48187constexpr int UpdateClientTest::kNumWorkerThreads_;
188
Sorin Jianucc048f892017-07-26 02:05:54189UpdateClientTest::UpdateClientTest() {
wafflesd2d9a332016-04-09 01:59:57190 PersistedData::RegisterPrefs(pref_->registry());
Jinho Bangda4e4282018-01-03 13:21:23191 metadata_ = std::make_unique<PersistedData>(pref_.get(), nullptr);
sorin9797aba2015-04-17 17:15:03192}
193
194UpdateClientTest::~UpdateClientTest() {
sorin9797aba2015-04-17 17:15:03195}
196
197void UpdateClientTest::RunThreads() {
198 runloop_.Run();
Sorin Jianuf40ab4b32017-10-06 22:53:41199 scoped_task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03200}
201
202base::FilePath UpdateClientTest::TestFilePath(const char* file) {
203 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:53204 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin9797aba2015-04-17 17:15:03205 return path.AppendASCII("components")
206 .AppendASCII("test")
207 .AppendASCII("data")
208 .AppendASCII("update_client")
209 .AppendASCII(file);
210}
211
212// Tests the scenario where one update check is done for one CRX. The CRX
213// has no update.
214TEST_F(UpdateClientTest, OneCrxNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53215 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03216 public:
Sorin Jianu7c22795b2018-04-26 22:16:52217 static std::vector<std::unique_ptr<CrxComponent>> Callback(
218 const std::vector<std::string>& ids) {
219 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
220 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:24221 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52222 crx->version = base::Version("0.9");
223 crx->installer = base::MakeRefCounted<TestInstaller>();
224 std::vector<std::unique_ptr<CrxComponent>> component;
225 component.push_back(std::move(crx));
226 return component;
sorin9797aba2015-04-17 17:15:03227 }
228 };
229
Sorin Jianua8926bf2018-03-09 21:02:53230 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03231 public:
Sorin Jianua8ef73d2017-11-02 16:55:17232 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41233 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17234 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03235 }
236 };
237
Sorin Jianua8926bf2018-03-09 21:02:53238 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03239 public:
dchengd0fc6aa92016-04-22 18:03:12240 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42241 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49242 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53243 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03244 }
245
Sorin Jianud69d4372018-02-07 19:44:22246 void CheckForUpdates(const std::string& session_id,
247 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17248 const IdToComponentPtrMap& components,
249 const std::string& additional_attributes,
250 bool enabled_component_updates,
251 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:22252 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:36253 EXPECT_TRUE(enabled_component_updates);
sorin30474f02017-04-27 00:45:48254 EXPECT_EQ(1u, ids_to_check.size());
255 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
256 EXPECT_EQ(id, ids_to_check.front());
257 EXPECT_EQ(1u, components.count(id));
258
259 auto& component = components.at(id);
260
Sorin Jianub41a592a2018-03-02 16:30:27261 EXPECT_TRUE(component->is_foreground());
sorin30474f02017-04-27 00:45:48262
sorin7cff6e52017-05-17 16:37:23263 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48264 result.extension_id = id;
265 result.status = "noupdate";
266 component->SetParseResult(result);
267
sorin9797aba2015-04-17 17:15:03268 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17269 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:03270 }
271 };
272
Sorin Jianua8926bf2018-03-09 21:02:53273 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03274 public:
dchengd0fc6aa92016-04-22 18:03:12275 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03276 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21277 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53278 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03279 }
280
Sorin Jianua8926bf2018-03-09 21:02:53281 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03282
sorin30474f02017-04-27 00:45:48283 private:
sorin9797aba2015-04-17 17:15:03284 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
285 };
286
Sorin Jianua8926bf2018-03-09 21:02:53287 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03288 public:
Sorin Jianua8926bf2018-03-09 21:02:53289 explicit MockPingManager(scoped_refptr<Configurator> config)
290 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54291
292 protected:
Sorin Jianua8926bf2018-03-09 21:02:53293 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin9797aba2015-04-17 17:15:03294 };
295
sorin30474f02017-04-27 00:45:48296 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43297 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53298 config(), base::MakeRefCounted<MockPingManager>(config()),
299 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:09300
sorin9797aba2015-04-17 17:15:03301 MockObserver observer;
302 InSequence seq;
303 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
304 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
305 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
306 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
307
308 update_client->AddObserver(&observer);
309
sorin30474f02017-04-27 00:45:48310 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:03311 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:53312 ids, base::BindOnce(&DataCallbackMock::Callback), true,
313 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03314
315 RunThreads();
316
317 update_client->RemoveObserver(&observer);
318}
319
320// Tests the scenario where two CRXs are checked for updates. On CRX has
321// an update, the other CRX does not.
322TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53323 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03324 public:
Sorin Jianu7c22795b2018-04-26 22:16:52325 static std::vector<std::unique_ptr<CrxComponent>> Callback(
326 const std::vector<std::string>& ids) {
327 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
328 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:24329 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52330 crx1->version = base::Version("0.9");
331 crx1->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03332
Sorin Jianu7c22795b2018-04-26 22:16:52333 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
334 crx2->name = "test_abag";
Sorin Jianucb4431a2018-04-30 20:59:24335 crx2->pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52336 crx2->version = base::Version("2.2");
337 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03338
Sorin Jianu7c22795b2018-04-26 22:16:52339 std::vector<std::unique_ptr<CrxComponent>> component;
340 component.push_back(std::move(crx1));
341 component.push_back(std::move(crx2));
342 return component;
sorin9797aba2015-04-17 17:15:03343 }
344 };
345
Sorin Jianua8926bf2018-03-09 21:02:53346 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03347 public:
Sorin Jianua8ef73d2017-11-02 16:55:17348 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41349 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17350 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03351 }
352 };
353
Sorin Jianua8926bf2018-03-09 21:02:53354 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03355 public:
dchengd0fc6aa92016-04-22 18:03:12356 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42357 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49358 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53359 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03360 }
361
Sorin Jianud69d4372018-02-07 19:44:22362 void CheckForUpdates(const std::string& session_id,
363 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17364 const IdToComponentPtrMap& components,
365 const std::string& additional_attributes,
366 bool enabled_component_updates,
367 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03368 /*
Sorin Jianua8926bf2018-03-09 21:02:53369 Mock the following response:
sorin9797aba2015-04-17 17:15:03370
371 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28372 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03373 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
374 <updatecheck status='ok'>
375 <urls>
376 <url codebase='http://localhost/download/'/>
377 </urls>
378 <manifest version='1.0' prodversionmin='11.0.1.0'>
379 <packages>
sorin74e70672016-02-03 03:13:10380 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
381 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
382 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03383 </packages>
384 </manifest>
385 </updatecheck>
386 </app>
387 </response>
388 */
Sorin Jianud69d4372018-02-07 19:44:22389 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48390 EXPECT_TRUE(enabled_component_updates);
391 EXPECT_EQ(2u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03392
sorin30474f02017-04-27 00:45:48393 {
394 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
395 EXPECT_EQ(id, ids_to_check[0]);
396 EXPECT_EQ(1u, components.count(id));
397
sorin7cff6e52017-05-17 16:37:23398 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48399 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
400 package.hash_sha256 =
401 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
402
sorin7cff6e52017-05-17 16:37:23403 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48404 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
405 result.status = "ok";
406 result.crx_urls.push_back(GURL("http://localhost/download/"));
407 result.manifest.version = "1.0";
408 result.manifest.browser_min_version = "11.0.1.0";
409 result.manifest.packages.push_back(package);
410
411 auto& component = components.at(id);
412 component->SetParseResult(result);
413
Sorin Jianub41a592a2018-03-02 16:30:27414 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:48415 }
416
417 {
418 const std::string id = "abagagagagagagagagagagagagagagag";
419 EXPECT_EQ(id, ids_to_check[1]);
420 EXPECT_EQ(1u, components.count(id));
421
sorin7cff6e52017-05-17 16:37:23422 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48423 result.extension_id = id;
424 result.status = "noupdate";
425
426 auto& component = components.at(id);
427 component->SetParseResult(result);
428
Sorin Jianub41a592a2018-03-02 16:30:27429 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:48430 }
sorin9797aba2015-04-17 17:15:03431
432 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17433 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:03434 }
435 };
436
Sorin Jianua8926bf2018-03-09 21:02:53437 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03438 public:
dchengd0fc6aa92016-04-22 18:03:12439 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03440 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21441 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53442 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03443 }
444
Sorin Jianua8926bf2018-03-09 21:02:53445 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03446
sorin30474f02017-04-27 00:45:48447 private:
sorin9797aba2015-04-17 17:15:03448 void DoStartDownload(const GURL& url) override {
449 DownloadMetrics download_metrics;
450 download_metrics.url = url;
451 download_metrics.downloader = DownloadMetrics::kNone;
452 download_metrics.error = 0;
453 download_metrics.downloaded_bytes = 1843;
454 download_metrics.total_bytes = 1843;
455 download_metrics.download_time_ms = 1000;
456
457 FilePath path;
458 EXPECT_TRUE(MakeTestFile(
459 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
460
461 Result result;
462 result.error = 0;
463 result.response = path;
464 result.downloaded_bytes = 1843;
465 result.total_bytes = 1843;
466
467 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53468 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:58469 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:03470
471 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53472 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:58473 base::Unretained(this), true, result,
474 download_metrics));
sorin9797aba2015-04-17 17:15:03475 }
476 };
477
Sorin Jianua8926bf2018-03-09 21:02:53478 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03479 public:
Sorin Jianua8926bf2018-03-09 21:02:53480 explicit MockPingManager(scoped_refptr<Configurator> config)
481 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54482
483 protected:
Sorin Jianua8926bf2018-03-09 21:02:53484 ~MockPingManager() override {
485 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:48486 EXPECT_EQ(1u, ping_data.size());
487 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
488 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
489 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
490 EXPECT_EQ(0, ping_data[0].error_category);
491 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03492 }
493 };
494
sorin30474f02017-04-27 00:45:48495 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43496 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53497 config(), base::MakeRefCounted<MockPingManager>(config()),
498 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:03499
500 MockObserver observer;
501 {
502 InSequence seq;
503 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
504 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
505 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
506 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
507 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:48508 "jebgalgnebhfojomionfpkfelancnnkf"))
509 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:03510 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
511 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
512 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
513 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
514 }
515 {
516 InSequence seq;
517 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
518 "abagagagagagagagagagagagagagagag")).Times(1);
519 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
520 "abagagagagagagagagagagagagagagag")).Times(1);
521 }
522
523 update_client->AddObserver(&observer);
524
sorin30474f02017-04-27 00:45:48525 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
526 "abagagagagagagagagagagagagagagag"};
sorin9797aba2015-04-17 17:15:03527 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:53528 ids, base::BindOnce(&DataCallbackMock::Callback), false,
529 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03530
531 RunThreads();
532
533 update_client->RemoveObserver(&observer);
534}
535
Sorin Jianucb4431a2018-04-30 20:59:24536// Tests the update check for two CRXs scenario when the second CRX does not
537// provide a CrxComponent instance. In this case, the update is handled as
538// if only one component were provided as an argument to the |Update| call
539// with the exception that the second component still fires an event such as
540// |COMPONENT_UPDATE_ERROR|.
541TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentData) {
Sorin Jianua8926bf2018-03-09 21:02:53542 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03543 public:
Sorin Jianu7c22795b2018-04-26 22:16:52544 static std::vector<std::unique_ptr<CrxComponent>> Callback(
545 const std::vector<std::string>& ids) {
Sorin Jianucb4431a2018-04-30 20:59:24546 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
547 crx->name = "test_jebg";
548 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
549 crx->version = base::Version("0.9");
550 crx->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03551
Sorin Jianu7c22795b2018-04-26 22:16:52552 std::vector<std::unique_ptr<CrxComponent>> component;
Sorin Jianucb4431a2018-04-30 20:59:24553 component.push_back(std::move(crx));
554 component.push_back(std::move(nullptr));
Sorin Jianu7c22795b2018-04-26 22:16:52555 return component;
sorin9797aba2015-04-17 17:15:03556 }
557 };
558
Sorin Jianua8926bf2018-03-09 21:02:53559 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03560 public:
Sorin Jianua8ef73d2017-11-02 16:55:17561 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41562 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17563 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03564 }
565 };
566
Sorin Jianua8926bf2018-03-09 21:02:53567 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03568 public:
dchengd0fc6aa92016-04-22 18:03:12569 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42570 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49571 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53572 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03573 }
574
Sorin Jianud69d4372018-02-07 19:44:22575 void CheckForUpdates(const std::string& session_id,
576 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17577 const IdToComponentPtrMap& components,
578 const std::string& additional_attributes,
579 bool enabled_component_updates,
580 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03581 /*
Sorin Jianua8926bf2018-03-09 21:02:53582 Mock the following response:
sorin9797aba2015-04-17 17:15:03583
584 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28585 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03586 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
587 <updatecheck status='ok'>
588 <urls>
589 <url codebase='http://localhost/download/'/>
590 </urls>
591 <manifest version='1.0' prodversionmin='11.0.1.0'>
592 <packages>
sorin74e70672016-02-03 03:13:10593 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
594 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
595 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03596 </packages>
597 </manifest>
598 </updatecheck>
599 </app>
sorin9797aba2015-04-17 17:15:03600 </response>
601 */
Sorin Jianud69d4372018-02-07 19:44:22602 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48603 EXPECT_TRUE(enabled_component_updates);
Sorin Jianucb4431a2018-04-30 20:59:24604 EXPECT_EQ(1u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03605
sorin30474f02017-04-27 00:45:48606 {
607 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
608 EXPECT_EQ(id, ids_to_check[0]);
609 EXPECT_EQ(1u, components.count(id));
sorin9797aba2015-04-17 17:15:03610
sorin7cff6e52017-05-17 16:37:23611 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48612 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
613 package.hash_sha256 =
614 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03615
sorin7cff6e52017-05-17 16:37:23616 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48617 result.extension_id = id;
618 result.status = "ok";
619 result.crx_urls.push_back(GURL("http://localhost/download/"));
620 result.manifest.version = "1.0";
621 result.manifest.browser_min_version = "11.0.1.0";
622 result.manifest.packages.push_back(package);
sorin9797aba2015-04-17 17:15:03623
sorin30474f02017-04-27 00:45:48624 auto& component = components.at(id);
625 component->SetParseResult(result);
626
Sorin Jianub41a592a2018-03-02 16:30:27627 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:48628 }
629
sorin9797aba2015-04-17 17:15:03630 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17631 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:03632 }
633 };
634
Sorin Jianua8926bf2018-03-09 21:02:53635 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03636 public:
dchengd0fc6aa92016-04-22 18:03:12637 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03638 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21639 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53640 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03641 }
642
Sorin Jianua8926bf2018-03-09 21:02:53643 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03644
sorin30474f02017-04-27 00:45:48645 private:
sorin9797aba2015-04-17 17:15:03646 void DoStartDownload(const GURL& url) override {
647 DownloadMetrics download_metrics;
648 FilePath path;
649 Result result;
650 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
651 download_metrics.url = url;
652 download_metrics.downloader = DownloadMetrics::kNone;
653 download_metrics.error = 0;
654 download_metrics.downloaded_bytes = 1843;
655 download_metrics.total_bytes = 1843;
656 download_metrics.download_time_ms = 1000;
657
658 EXPECT_TRUE(MakeTestFile(
659 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
660
661 result.error = 0;
662 result.response = path;
663 result.downloaded_bytes = 1843;
664 result.total_bytes = 1843;
sorin9797aba2015-04-17 17:15:03665 } else {
666 NOTREACHED();
667 }
668
669 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53670 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:58671 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:03672
673 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53674 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianua8ef73d2017-11-02 16:55:17675 base::Unretained(this), true, result,
676 download_metrics));
sorin9797aba2015-04-17 17:15:03677 }
678 };
679
Sorin Jianua8926bf2018-03-09 21:02:53680 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03681 public:
Sorin Jianua8926bf2018-03-09 21:02:53682 explicit MockPingManager(scoped_refptr<Configurator> config)
683 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54684
685 protected:
Sorin Jianua8926bf2018-03-09 21:02:53686 ~MockPingManager() override {
687 const auto ping_data = MockPingManagerImpl::ping_data();
Sorin Jianucb4431a2018-04-30 20:59:24688 EXPECT_EQ(1u, ping_data.size());
sorin30474f02017-04-27 00:45:48689 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
690 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
691 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
692 EXPECT_EQ(0, ping_data[0].error_category);
693 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03694 }
695 };
696
sorin30474f02017-04-27 00:45:48697 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43698 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53699 config(), base::MakeRefCounted<MockPingManager>(config()),
700 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:03701
702 MockObserver observer;
703 {
704 InSequence seq;
705 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
706 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
707 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
708 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
709 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:48710 "jebgalgnebhfojomionfpkfelancnnkf"))
711 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:03712 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
713 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
715 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
716 }
717 {
718 InSequence seq;
Sorin Jianucb4431a2018-04-30 20:59:24719 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorin30474f02017-04-27 00:45:48720 "ihfokbkgjpifnbbojhneepfflplebdkc"))
Sorin Jianucb4431a2018-04-30 20:59:24721 .Times(1);
722 }
723
724 update_client->AddObserver(&observer);
725
726 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
727 "ihfokbkgjpifnbbojhneepfflplebdkc"};
728 update_client->Update(
729 ids, base::BindOnce(&DataCallbackMock::Callback), false,
730 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
731
732 RunThreads();
733
734 update_client->RemoveObserver(&observer);
735}
736
737// Tests the update check for two CRXs scenario when no CrxComponent data is
738// provided for either component. In this case, no update check occurs, and
739// |COMPONENT_UPDATE_ERROR| event fires for both components.
740TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentDataAtAll) {
741 class DataCallbackMock {
742 public:
743 static std::vector<std::unique_ptr<CrxComponent>> Callback(
744 const std::vector<std::string>& ids) {
745 std::vector<std::unique_ptr<CrxComponent>> component;
746 component.push_back(std::move(nullptr));
747 component.push_back(std::move(nullptr));
748 return component;
749 }
750 };
751
752 class CompletionCallbackMock {
753 public:
754 static void Callback(base::OnceClosure quit_closure, Error error) {
755 EXPECT_EQ(Error::NONE, error);
756 std::move(quit_closure).Run();
757 }
758 };
759
760 class MockUpdateChecker : public UpdateChecker {
761 public:
762 static std::unique_ptr<UpdateChecker> Create(
763 scoped_refptr<Configurator> config,
764 PersistedData* metadata) {
765 return std::make_unique<MockUpdateChecker>();
766 }
767
768 void CheckForUpdates(const std::string& session_id,
769 const std::vector<std::string>& ids_to_check,
770 const IdToComponentPtrMap& components,
771 const std::string& additional_attributes,
772 bool enabled_component_updates,
773 UpdateCheckCallback update_check_callback) override {
774 NOTREACHED();
775 }
776 };
777
778 class MockCrxDownloader : public CrxDownloader {
779 public:
780 static std::unique_ptr<CrxDownloader> Create(
781 bool is_background_download,
782 scoped_refptr<net::URLRequestContextGetter> context_getter) {
783 return std::make_unique<MockCrxDownloader>();
784 }
785
786 MockCrxDownloader() : CrxDownloader(nullptr) {}
787
788 private:
789 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
790 };
791
792 class MockPingManager : public MockPingManagerImpl {
793 public:
794 explicit MockPingManager(scoped_refptr<Configurator> config)
795 : MockPingManagerImpl(config) {}
796
797 protected:
798 ~MockPingManager() override {
799 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
800 }
801 };
802
803 scoped_refptr<UpdateClient> update_client =
804 base::MakeRefCounted<UpdateClientImpl>(
805 config(), base::MakeRefCounted<MockPingManager>(config()),
806 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
807
808 MockObserver observer;
809 {
810 InSequence seq;
811 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
812 "jebgalgnebhfojomionfpkfelancnnkf"))
813 .Times(1);
814 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
815 "ihfokbkgjpifnbbojhneepfflplebdkc"))
816 .Times(1);
sorin9797aba2015-04-17 17:15:03817 }
818
819 update_client->AddObserver(&observer);
820
sorin30474f02017-04-27 00:45:48821 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
822 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:03823 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:53824 ids, base::BindOnce(&DataCallbackMock::Callback), false,
825 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03826
827 RunThreads();
828
829 update_client->RemoveObserver(&observer);
830}
831
sorin6bb8de42015-06-03 00:23:27832// Tests the scenario where there is a download timeout for the first
833// CRX. The update for the first CRX fails. The update client waits before
834// attempting the update for the second CRX. This update succeeds.
835TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
Sorin Jianua8926bf2018-03-09 21:02:53836 class DataCallbackMock {
sorin6bb8de42015-06-03 00:23:27837 public:
Sorin Jianu7c22795b2018-04-26 22:16:52838 static std::vector<std::unique_ptr<CrxComponent>> Callback(
839 const std::vector<std::string>& ids) {
840 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
841 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:24842 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52843 crx1->version = base::Version("0.9");
844 crx1->installer = base::MakeRefCounted<TestInstaller>();
sorin6bb8de42015-06-03 00:23:27845
Sorin Jianu7c22795b2018-04-26 22:16:52846 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
847 crx2->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:24848 crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52849 crx2->version = base::Version("0.8");
850 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorin6bb8de42015-06-03 00:23:27851
Sorin Jianu7c22795b2018-04-26 22:16:52852 std::vector<std::unique_ptr<CrxComponent>> component;
853 component.push_back(std::move(crx1));
854 component.push_back(std::move(crx2));
855 return component;
sorin6bb8de42015-06-03 00:23:27856 }
857 };
858
Sorin Jianua8926bf2018-03-09 21:02:53859 class CompletionCallbackMock {
sorin6bb8de42015-06-03 00:23:27860 public:
Sorin Jianua8ef73d2017-11-02 16:55:17861 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41862 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17863 std::move(quit_closure).Run();
sorin6bb8de42015-06-03 00:23:27864 }
865 };
866
Sorin Jianua8926bf2018-03-09 21:02:53867 class MockUpdateChecker : public UpdateChecker {
sorin6bb8de42015-06-03 00:23:27868 public:
dchengd0fc6aa92016-04-22 18:03:12869 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42870 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49871 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53872 return std::make_unique<MockUpdateChecker>();
sorin6bb8de42015-06-03 00:23:27873 }
874
Sorin Jianud69d4372018-02-07 19:44:22875 void CheckForUpdates(const std::string& session_id,
876 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17877 const IdToComponentPtrMap& components,
878 const std::string& additional_attributes,
879 bool enabled_component_updates,
880 UpdateCheckCallback update_check_callback) override {
sorin6bb8de42015-06-03 00:23:27881 /*
Sorin Jianua8926bf2018-03-09 21:02:53882 Mock the following response:
sorin6bb8de42015-06-03 00:23:27883
884 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28885 <response protocol='3.1'>
sorin6bb8de42015-06-03 00:23:27886 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
887 <updatecheck status='ok'>
888 <urls>
889 <url codebase='http://localhost/download/'/>
890 </urls>
891 <manifest version='1.0' prodversionmin='11.0.1.0'>
892 <packages>
sorin74e70672016-02-03 03:13:10893 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
894 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
895 7c9b12cb7cc067667bde87'/>
sorin6bb8de42015-06-03 00:23:27896 </packages>
897 </manifest>
898 </updatecheck>
899 </app>
900 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
901 <updatecheck status='ok'>
902 <urls>
903 <url codebase='http://localhost/download/'/>
904 </urls>
905 <manifest version='1.0' prodversionmin='11.0.1.0'>
906 <packages>
sorin74e70672016-02-03 03:13:10907 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
908 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
909 309f156ea6d27229c0b3f9'/>
sorin6bb8de42015-06-03 00:23:27910 </packages>
911 </manifest>
912 </updatecheck>
913 </app>
914 </response>
915 */
sorin6bb8de42015-06-03 00:23:27916
Sorin Jianud69d4372018-02-07 19:44:22917 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48918 EXPECT_TRUE(enabled_component_updates);
919 EXPECT_EQ(2u, ids_to_check.size());
sorin6bb8de42015-06-03 00:23:27920
sorin30474f02017-04-27 00:45:48921 {
922 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
923 EXPECT_EQ(id, ids_to_check[0]);
924 EXPECT_EQ(1u, components.count(id));
sorin6bb8de42015-06-03 00:23:27925
sorin7cff6e52017-05-17 16:37:23926 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48927 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
928 package.hash_sha256 =
929 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin6bb8de42015-06-03 00:23:27930
sorin7cff6e52017-05-17 16:37:23931 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48932 result.extension_id = id;
933 result.status = "ok";
934 result.crx_urls.push_back(GURL("http://localhost/download/"));
935 result.manifest.version = "1.0";
936 result.manifest.browser_min_version = "11.0.1.0";
937 result.manifest.packages.push_back(package);
938
939 auto& component = components.at(id);
940 component->SetParseResult(result);
941 }
942
943 {
944 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
945 EXPECT_EQ(id, ids_to_check[1]);
946 EXPECT_EQ(1u, components.count(id));
947
sorin7cff6e52017-05-17 16:37:23948 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48949 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
950 package.hash_sha256 =
951 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
952
sorin7cff6e52017-05-17 16:37:23953 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48954 result.extension_id = id;
955 result.status = "ok";
956 result.crx_urls.push_back(GURL("http://localhost/download/"));
957 result.manifest.version = "1.0";
958 result.manifest.browser_min_version = "11.0.1.0";
959 result.manifest.packages.push_back(package);
960
961 auto& component = components.at(id);
962 component->SetParseResult(result);
963 }
sorin6bb8de42015-06-03 00:23:27964
965 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17966 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin6bb8de42015-06-03 00:23:27967 }
968 };
969
Sorin Jianua8926bf2018-03-09 21:02:53970 class MockCrxDownloader : public CrxDownloader {
sorin6bb8de42015-06-03 00:23:27971 public:
dchengd0fc6aa92016-04-22 18:03:12972 static std::unique_ptr<CrxDownloader> Create(
sorin6bb8de42015-06-03 00:23:27973 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21974 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53975 return std::make_unique<MockCrxDownloader>();
sorin6bb8de42015-06-03 00:23:27976 }
977
Sorin Jianua8926bf2018-03-09 21:02:53978 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin6bb8de42015-06-03 00:23:27979
sorin30474f02017-04-27 00:45:48980 private:
sorin6bb8de42015-06-03 00:23:27981 void DoStartDownload(const GURL& url) override {
982 DownloadMetrics download_metrics;
983 FilePath path;
984 Result result;
985 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
986 download_metrics.url = url;
987 download_metrics.downloader = DownloadMetrics::kNone;
988 download_metrics.error = -118;
989 download_metrics.downloaded_bytes = 0;
990 download_metrics.total_bytes = 0;
991 download_metrics.download_time_ms = 1000;
992
Sorin Jianu52de5fa2017-10-09 23:19:33993 // The result must not include a file path in the case of errors.
sorin6bb8de42015-06-03 00:23:27994 result.error = -118;
sorin6bb8de42015-06-03 00:23:27995 result.downloaded_bytes = 0;
996 result.total_bytes = 0;
997 } else if (url.path() ==
998 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
999 download_metrics.url = url;
1000 download_metrics.downloader = DownloadMetrics::kNone;
1001 download_metrics.error = 0;
1002 download_metrics.downloaded_bytes = 53638;
1003 download_metrics.total_bytes = 53638;
1004 download_metrics.download_time_ms = 2000;
1005
1006 EXPECT_TRUE(MakeTestFile(
1007 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1008
1009 result.error = 0;
1010 result.response = path;
1011 result.downloaded_bytes = 53638;
1012 result.total_bytes = 53638;
1013 } else {
1014 NOTREACHED();
1015 }
1016
1017 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531018 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:581019 base::Unretained(this), result));
sorin6bb8de42015-06-03 00:23:271020
1021 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531022 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581023 base::Unretained(this), true, result,
1024 download_metrics));
sorin6bb8de42015-06-03 00:23:271025 }
1026 };
1027
Sorin Jianua8926bf2018-03-09 21:02:531028 class MockPingManager : public MockPingManagerImpl {
sorin6bb8de42015-06-03 00:23:271029 public:
Sorin Jianua8926bf2018-03-09 21:02:531030 explicit MockPingManager(scoped_refptr<Configurator> config)
1031 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541032
1033 protected:
Sorin Jianua8926bf2018-03-09 21:02:531034 ~MockPingManager() override {
1035 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481036 EXPECT_EQ(2u, ping_data.size());
1037 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1038 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1039 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
1040 EXPECT_EQ(1, ping_data[0].error_category);
1041 EXPECT_EQ(-118, ping_data[0].error_code);
1042 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1043 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
1044 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
1045 EXPECT_EQ(0, ping_data[1].error_category);
1046 EXPECT_EQ(0, ping_data[1].error_code);
sorin6bb8de42015-06-03 00:23:271047 }
1048 };
1049
sorin30474f02017-04-27 00:45:481050 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431051 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531052 config(), base::MakeRefCounted<MockPingManager>(config()),
1053 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin6bb8de42015-06-03 00:23:271054
1055 MockObserver observer;
1056 {
1057 InSequence seq;
1058 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1059 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1060 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1061 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1062 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481063 "jebgalgnebhfojomionfpkfelancnnkf"))
1064 .Times(AtLeast(1));
Sorin Jianucbb10e12018-01-23 18:01:441065 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1066 "jebgalgnebhfojomionfpkfelancnnkf"))
Sorin Jianuafcb70dd2018-05-16 20:14:151067 .Times(1)
1068 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
1069 CrxUpdateItem item;
1070 update_client->GetCrxUpdateState(id, &item);
1071 EXPECT_EQ(ComponentState::kUpdateError, item.state);
1072 EXPECT_EQ(1, item.error_category);
1073 EXPECT_EQ(-118, item.error_code);
1074 EXPECT_EQ(0, item.extra_code1);
1075 }));
sorin6bb8de42015-06-03 00:23:271076 }
1077 {
1078 InSequence seq;
1079 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1080 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1081 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1082 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1083 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
1084 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1085 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481086 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1087 .Times(AtLeast(1));
sorin6bb8de42015-06-03 00:23:271088 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1089 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1090 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1091 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1092 }
1093
1094 update_client->AddObserver(&observer);
1095
sorin30474f02017-04-27 00:45:481096 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1097 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin6bb8de42015-06-03 00:23:271098
1099 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:531100 ids, base::BindOnce(&DataCallbackMock::Callback), false,
1101 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin6bb8de42015-06-03 00:23:271102
1103 RunThreads();
1104
1105 update_client->RemoveObserver(&observer);
sorin6bb8de42015-06-03 00:23:271106}
1107
sorin9797aba2015-04-17 17:15:031108// Tests the differential update scenario for one CRX.
1109TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:531110 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031111 public:
Sorin Jianu7c22795b2018-04-26 22:16:521112 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1113 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:031114 static int num_calls = 0;
1115
1116 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:481117 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431118 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:031119
1120 ++num_calls;
1121
Sorin Jianu7c22795b2018-04-26 22:16:521122 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1123 crx->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:241124 crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521125 crx->installer = installer;
sorin9797aba2015-04-17 17:15:031126 if (num_calls == 1) {
Sorin Jianu7c22795b2018-04-26 22:16:521127 crx->version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031128 } else if (num_calls == 2) {
Sorin Jianu7c22795b2018-04-26 22:16:521129 crx->version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031130 } else {
1131 NOTREACHED();
1132 }
1133
Sorin Jianu7c22795b2018-04-26 22:16:521134 std::vector<std::unique_ptr<CrxComponent>> component;
1135 component.push_back(std::move(crx));
1136 return component;
sorin9797aba2015-04-17 17:15:031137 }
1138 };
1139
Sorin Jianua8926bf2018-03-09 21:02:531140 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031141 public:
Sorin Jianua8ef73d2017-11-02 16:55:171142 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411143 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171144 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031145 }
1146 };
1147
Sorin Jianua8926bf2018-03-09 21:02:531148 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031149 public:
dchengd0fc6aa92016-04-22 18:03:121150 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421151 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491152 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531153 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031154 }
1155
Sorin Jianud69d4372018-02-07 19:44:221156 void CheckForUpdates(const std::string& session_id,
1157 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171158 const IdToComponentPtrMap& components,
1159 const std::string& additional_attributes,
1160 bool enabled_component_updates,
1161 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:221162 EXPECT_FALSE(session_id.empty());
1163
sorin9797aba2015-04-17 17:15:031164 static int num_call = 0;
1165 ++num_call;
1166
sorin7cff6e52017-05-17 16:37:231167 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:031168
1169 if (num_call == 1) {
1170 /*
Sorin Jianua8926bf2018-03-09 21:02:531171 Mock the following response:
sorin9797aba2015-04-17 17:15:031172 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281173 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031174 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1175 <updatecheck status='ok'>
1176 <urls>
1177 <url codebase='http://localhost/download/'/>
1178 </urls>
1179 <manifest version='1.0' prodversionmin='11.0.1.0'>
1180 <packages>
sorin74e70672016-02-03 03:13:101181 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1182 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1183 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031184 </packages>
1185 </manifest>
1186 </updatecheck>
1187 </app>
1188 </response>
1189 */
sorin30474f02017-04-27 00:45:481190 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1191 EXPECT_EQ(id, ids_to_check[0]);
1192 EXPECT_EQ(1u, components.count(id));
1193
sorin7cff6e52017-05-17 16:37:231194 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031195 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101196 package.hash_sha256 =
1197 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin30474f02017-04-27 00:45:481198
sorin7cff6e52017-05-17 16:37:231199 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481200 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171201 result.status = "ok";
sorin9797aba2015-04-17 17:15:031202 result.crx_urls.push_back(GURL("http://localhost/download/"));
1203 result.manifest.version = "1.0";
1204 result.manifest.browser_min_version = "11.0.1.0";
1205 result.manifest.packages.push_back(package);
sorin30474f02017-04-27 00:45:481206
1207 auto& component = components.at(id);
1208 component->SetParseResult(result);
sorin9797aba2015-04-17 17:15:031209 } else if (num_call == 2) {
1210 /*
Sorin Jianua8926bf2018-03-09 21:02:531211 Mock the following response:
sorin9797aba2015-04-17 17:15:031212 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281213 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031214 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1215 <updatecheck status='ok'>
1216 <urls>
1217 <url codebase='http://localhost/download/'/>
1218 <url codebasediff='http://localhost/download/'/>
1219 </urls>
1220 <manifest version='2.0' prodversionmin='11.0.1.0'>
1221 <packages>
1222 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1223 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101224 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1225 0ecde26c262bad942b112990'
1226 fp='22'
1227 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261228 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031229 </packages>
1230 </manifest>
1231 </updatecheck>
1232 </app>
1233 </response>
1234 */
sorin30474f02017-04-27 00:45:481235 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1236 EXPECT_EQ(id, ids_to_check[0]);
1237 EXPECT_EQ(1u, components.count(id));
1238
sorin7cff6e52017-05-17 16:37:231239 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031240 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1241 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101242 package.hash_sha256 =
1243 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1244 package.hashdiff_sha256 =
1245 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031246 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:481247
sorin7cff6e52017-05-17 16:37:231248 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481249 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171250 result.status = "ok";
sorin9797aba2015-04-17 17:15:031251 result.crx_urls.push_back(GURL("http://localhost/download/"));
1252 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1253 result.manifest.version = "2.0";
1254 result.manifest.browser_min_version = "11.0.1.0";
1255 result.manifest.packages.push_back(package);
sorin30474f02017-04-27 00:45:481256
1257 auto& component = components.at(id);
1258 component->SetParseResult(result);
sorin9797aba2015-04-17 17:15:031259 } else {
1260 NOTREACHED();
1261 }
1262
1263 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:171264 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:031265 }
1266 };
1267
Sorin Jianua8926bf2018-03-09 21:02:531268 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031269 public:
dchengd0fc6aa92016-04-22 18:03:121270 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031271 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211272 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531273 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031274 }
1275
Sorin Jianua8926bf2018-03-09 21:02:531276 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031277
sorin30474f02017-04-27 00:45:481278 private:
sorin9797aba2015-04-17 17:15:031279 void DoStartDownload(const GURL& url) override {
1280 DownloadMetrics download_metrics;
1281 FilePath path;
1282 Result result;
1283 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1284 download_metrics.url = url;
1285 download_metrics.downloader = DownloadMetrics::kNone;
1286 download_metrics.error = 0;
1287 download_metrics.downloaded_bytes = 53638;
1288 download_metrics.total_bytes = 53638;
1289 download_metrics.download_time_ms = 2000;
1290
1291 EXPECT_TRUE(MakeTestFile(
1292 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1293
1294 result.error = 0;
1295 result.response = path;
1296 result.downloaded_bytes = 53638;
1297 result.total_bytes = 53638;
1298 } else if (url.path() ==
1299 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1300 download_metrics.url = url;
1301 download_metrics.downloader = DownloadMetrics::kNone;
1302 download_metrics.error = 0;
1303 download_metrics.downloaded_bytes = 2105;
1304 download_metrics.total_bytes = 2105;
1305 download_metrics.download_time_ms = 1000;
1306
1307 EXPECT_TRUE(MakeTestFile(
1308 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1309
1310 result.error = 0;
1311 result.response = path;
1312 result.downloaded_bytes = 2105;
1313 result.total_bytes = 2105;
1314 } else {
1315 NOTREACHED();
1316 }
1317
1318 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531319 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:581320 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:031321
1322 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531323 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581324 base::Unretained(this), true, result,
1325 download_metrics));
sorin9797aba2015-04-17 17:15:031326 }
1327 };
1328
Sorin Jianua8926bf2018-03-09 21:02:531329 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031330 public:
Sorin Jianua8926bf2018-03-09 21:02:531331 explicit MockPingManager(scoped_refptr<Configurator> config)
1332 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541333
1334 protected:
Sorin Jianua8926bf2018-03-09 21:02:531335 ~MockPingManager() override {
1336 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481337 EXPECT_EQ(2u, ping_data.size());
1338 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
1339 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
1340 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
1341 EXPECT_EQ(0, ping_data[0].error_category);
1342 EXPECT_EQ(0, ping_data[0].error_code);
1343 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1344 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
1345 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
1346 EXPECT_FALSE(ping_data[1].diff_update_failed);
1347 EXPECT_EQ(0, ping_data[1].diff_error_category);
1348 EXPECT_EQ(0, ping_data[1].diff_error_code);
1349 EXPECT_EQ(0, ping_data[1].error_category);
1350 EXPECT_EQ(0, ping_data[1].error_code);
sorin9797aba2015-04-17 17:15:031351 }
1352 };
1353
sorin30474f02017-04-27 00:45:481354 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431355 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531356 config(), base::MakeRefCounted<MockPingManager>(config()),
1357 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031358
1359 MockObserver observer;
1360 {
1361 InSequence seq;
1362 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1363 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1364 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1365 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1366 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481367 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1368 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031369 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1370 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1371 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1372 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1373 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1374 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1375 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1376 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1377 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481378 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1379 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031380 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1381 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1382 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1383 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1384 }
1385
1386 update_client->AddObserver(&observer);
1387
sorin30474f02017-04-27 00:45:481388 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031389 {
1390 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531391 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271392 false,
Sorin Jianua8926bf2018-03-09 21:02:531393 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171394 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031395 runloop.Run();
1396 }
1397
1398 {
1399 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531400 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271401 false,
Sorin Jianua8926bf2018-03-09 21:02:531402 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171403 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031404 runloop.Run();
1405 }
1406
1407 update_client->RemoveObserver(&observer);
1408}
1409
1410// Tests the update scenario for one CRX where the CRX installer returns
Sorin Jianuf40ab4b32017-10-06 22:53:411411// an error. Tests that the |unpack_path| argument refers to a valid path
1412// then |Install| is called, then tests that the |unpack| path is deleted
1413// by the |update_client| code before the test ends.
sorin9797aba2015-04-17 17:15:031414TEST_F(UpdateClientTest, OneCrxInstallError) {
1415 class MockInstaller : public CrxInstaller {
1416 public:
1417 MOCK_METHOD1(OnUpdateError, void(int error));
Sorin Jianua8ef73d2017-11-02 16:55:171418 MOCK_METHOD2(DoInstall,
Sorin Jianu7aa6d1f2017-10-13 20:29:291419 void(const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:411420 const Callback& callback));
sorin9797aba2015-04-17 17:15:031421 MOCK_METHOD2(GetInstalledFile,
1422 bool(const std::string& file, base::FilePath* installed_file));
1423 MOCK_METHOD0(Uninstall, bool());
1424
Sorin Jianua8ef73d2017-11-02 16:55:171425 void Install(const base::FilePath& unpack_path,
1426 const std::string& public_key,
Daniel Cheng67848522018-04-27 22:04:411427 Callback callback) override {
Sorin Jianua8ef73d2017-11-02 16:55:171428 DoInstall(unpack_path, std::move(callback));
1429
Sorin Jianu23f70f752017-05-30 16:21:581430 unpack_path_ = unpack_path;
1431 EXPECT_TRUE(base::DirectoryExists(unpack_path_));
Sorin Jianuf40ab4b32017-10-06 22:53:411432 base::PostTaskWithTraits(
1433 FROM_HERE, {base::MayBlock()},
Sorin Jianua8ef73d2017-11-02 16:55:171434 base::BindOnce(std::move(callback),
Sorin Jianuf40ab4b32017-10-06 22:53:411435 CrxInstaller::Result(InstallError::GENERIC_ERROR)));
sorin9797aba2015-04-17 17:15:031436 }
1437
1438 protected:
Sorin Jianu23f70f752017-05-30 16:21:581439 ~MockInstaller() override {
1440 // The unpack path is deleted unconditionally by the component state code,
1441 // which is driving this installer. Therefore, the unpack path must not
1442 // exist when this object is destroyed.
1443 if (!unpack_path_.empty())
1444 EXPECT_FALSE(base::DirectoryExists(unpack_path_));
1445 }
1446
1447 private:
1448 // Contains the |unpack_path| argument of the Install call.
1449 base::FilePath unpack_path_;
sorin9797aba2015-04-17 17:15:031450 };
1451
Sorin Jianua8926bf2018-03-09 21:02:531452 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031453 public:
Sorin Jianu7c22795b2018-04-26 22:16:521454 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1455 const std::vector<std::string>& ids) {
sorin30474f02017-04-27 00:45:481456 scoped_refptr<MockInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431457 base::MakeRefCounted<MockInstaller>();
sorin9797aba2015-04-17 17:15:031458
1459 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
Sorin Jianua8ef73d2017-11-02 16:55:171460 EXPECT_CALL(*installer, DoInstall(_, _)).Times(1);
sorin9797aba2015-04-17 17:15:031461 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
1462 EXPECT_CALL(*installer, Uninstall()).Times(0);
1463
Sorin Jianu7c22795b2018-04-26 22:16:521464 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1465 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:241466 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521467 crx->version = base::Version("0.9");
1468 crx->installer = installer;
1469
1470 std::vector<std::unique_ptr<CrxComponent>> component;
1471 component.push_back(std::move(crx));
1472 return component;
sorin9797aba2015-04-17 17:15:031473 }
1474 };
1475
Sorin Jianua8926bf2018-03-09 21:02:531476 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031477 public:
Sorin Jianua8ef73d2017-11-02 16:55:171478 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411479 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171480 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031481 }
1482 };
1483
Sorin Jianua8926bf2018-03-09 21:02:531484 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031485 public:
dchengd0fc6aa92016-04-22 18:03:121486 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421487 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491488 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531489 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031490 }
1491
Sorin Jianud69d4372018-02-07 19:44:221492 void CheckForUpdates(const std::string& session_id,
1493 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171494 const IdToComponentPtrMap& components,
1495 const std::string& additional_attributes,
1496 bool enabled_component_updates,
1497 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:031498 /*
Sorin Jianua8926bf2018-03-09 21:02:531499 Mock the following response:
sorin9797aba2015-04-17 17:15:031500
1501 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281502 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031503 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1504 <updatecheck status='ok'>
1505 <urls>
1506 <url codebase='http://localhost/download/'/>
1507 </urls>
1508 <manifest version='1.0' prodversionmin='11.0.1.0'>
1509 <packages>
sorin74e70672016-02-03 03:13:101510 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1511 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1512 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:031513 </packages>
1514 </manifest>
1515 </updatecheck>
1516 </app>
1517 </response>
1518 */
Sorin Jianud69d4372018-02-07 19:44:221519 EXPECT_FALSE(session_id.empty());
1520
sorin30474f02017-04-27 00:45:481521 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
1522 EXPECT_EQ(id, ids_to_check[0]);
1523 EXPECT_EQ(1u, components.count(id));
1524
sorin7cff6e52017-05-17 16:37:231525 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031526 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101527 package.hash_sha256 =
1528 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin30474f02017-04-27 00:45:481529
sorin7cff6e52017-05-17 16:37:231530 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481531 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171532 result.status = "ok";
sorin9797aba2015-04-17 17:15:031533 result.crx_urls.push_back(GURL("http://localhost/download/"));
1534 result.manifest.version = "1.0";
1535 result.manifest.browser_min_version = "11.0.1.0";
1536 result.manifest.packages.push_back(package);
1537
sorin30474f02017-04-27 00:45:481538 auto& component = components.at(id);
1539 component->SetParseResult(result);
sorin9797aba2015-04-17 17:15:031540
1541 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:171542 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:031543 }
1544 };
1545
Sorin Jianua8926bf2018-03-09 21:02:531546 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031547 public:
dchengd0fc6aa92016-04-22 18:03:121548 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031549 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211550 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531551 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031552 }
1553
Sorin Jianua8926bf2018-03-09 21:02:531554 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031555
sorin30474f02017-04-27 00:45:481556 private:
sorin9797aba2015-04-17 17:15:031557 void DoStartDownload(const GURL& url) override {
1558 DownloadMetrics download_metrics;
1559 download_metrics.url = url;
1560 download_metrics.downloader = DownloadMetrics::kNone;
1561 download_metrics.error = 0;
1562 download_metrics.downloaded_bytes = 1843;
1563 download_metrics.total_bytes = 1843;
1564 download_metrics.download_time_ms = 1000;
1565
1566 FilePath path;
1567 EXPECT_TRUE(MakeTestFile(
1568 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1569
1570 Result result;
1571 result.error = 0;
1572 result.response = path;
1573 result.downloaded_bytes = 1843;
1574 result.total_bytes = 1843;
1575
1576 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531577 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianua8ef73d2017-11-02 16:55:171578 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:031579
1580 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531581 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581582 base::Unretained(this), true, result,
1583 download_metrics));
sorin9797aba2015-04-17 17:15:031584 }
1585 };
1586
Sorin Jianua8926bf2018-03-09 21:02:531587 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031588 public:
Sorin Jianua8926bf2018-03-09 21:02:531589 explicit MockPingManager(scoped_refptr<Configurator> config)
1590 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541591
1592 protected:
Sorin Jianua8926bf2018-03-09 21:02:531593 ~MockPingManager() override {
1594 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481595 EXPECT_EQ(1u, ping_data.size());
1596 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1597 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1598 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Sorin Jianuafcb70dd2018-05-16 20:14:151599 EXPECT_EQ(3, ping_data[0].error_category); // kInstall.
sorin30474f02017-04-27 00:45:481600 EXPECT_EQ(9, ping_data[0].error_code); // kInstallerError.
sorin9797aba2015-04-17 17:15:031601 }
1602 };
1603
sorin30474f02017-04-27 00:45:481604 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431605 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531606 config(), base::MakeRefCounted<MockPingManager>(config()),
1607 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031608
1609 MockObserver observer;
1610 {
1611 InSequence seq;
1612 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1613 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1614 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1615 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1616 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481617 "jebgalgnebhfojomionfpkfelancnnkf"))
1618 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031619 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1620 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
Sorin Jianucbb10e12018-01-23 18:01:441621 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1622 "jebgalgnebhfojomionfpkfelancnnkf"))
1623 .Times(1);
sorin9797aba2015-04-17 17:15:031624 }
1625
1626 update_client->AddObserver(&observer);
1627
sorin30474f02017-04-27 00:45:481628 std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:031629 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:531630 ids, base::BindOnce(&DataCallbackMock::Callback), false,
1631 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031632
1633 RunThreads();
1634
1635 update_client->RemoveObserver(&observer);
1636}
1637
1638// Tests the fallback from differential to full update scenario for one CRX.
1639TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
Sorin Jianua8926bf2018-03-09 21:02:531640 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031641 public:
Sorin Jianu7c22795b2018-04-26 22:16:521642 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1643 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:031644 static int num_calls = 0;
1645
1646 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:481647 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431648 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:031649
1650 ++num_calls;
1651
Sorin Jianu7c22795b2018-04-26 22:16:521652 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1653 crx->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:241654 crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521655 crx->installer = installer;
sorin9797aba2015-04-17 17:15:031656 if (num_calls == 1) {
Sorin Jianu7c22795b2018-04-26 22:16:521657 crx->version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031658 } else if (num_calls == 2) {
Sorin Jianu7c22795b2018-04-26 22:16:521659 crx->version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031660 } else {
1661 NOTREACHED();
1662 }
1663
Sorin Jianu7c22795b2018-04-26 22:16:521664 std::vector<std::unique_ptr<CrxComponent>> component;
1665 component.push_back(std::move(crx));
1666 return component;
sorin9797aba2015-04-17 17:15:031667 }
1668 };
1669
Sorin Jianua8926bf2018-03-09 21:02:531670 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031671 public:
Sorin Jianua8ef73d2017-11-02 16:55:171672 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411673 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171674 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031675 }
1676 };
1677
Sorin Jianua8926bf2018-03-09 21:02:531678 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031679 public:
dchengd0fc6aa92016-04-22 18:03:121680 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421681 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491682 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531683 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031684 }
1685
Sorin Jianud69d4372018-02-07 19:44:221686 void CheckForUpdates(const std::string& session_id,
1687 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171688 const IdToComponentPtrMap& components,
1689 const std::string& additional_attributes,
1690 bool enabled_component_updates,
1691 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:221692 EXPECT_FALSE(session_id.empty());
1693
sorin9797aba2015-04-17 17:15:031694 static int num_call = 0;
1695 ++num_call;
1696
sorin7cff6e52017-05-17 16:37:231697 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:031698
1699 if (num_call == 1) {
1700 /*
Sorin Jianua8926bf2018-03-09 21:02:531701 Mock the following response:
sorin9797aba2015-04-17 17:15:031702 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281703 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031704 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1705 <updatecheck status='ok'>
1706 <urls>
1707 <url codebase='http://localhost/download/'/>
1708 </urls>
1709 <manifest version='1.0' prodversionmin='11.0.1.0'>
1710 <packages>
sorin74e70672016-02-03 03:13:101711 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1712 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
sorin30474f02017-04-27 00:45:481713 3f309f156ea6d27229c0b3f9'
1714 fp='1'/>
sorin9797aba2015-04-17 17:15:031715 </packages>
1716 </manifest>
1717 </updatecheck>
1718 </app>
1719 </response>
1720 */
sorin30474f02017-04-27 00:45:481721 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1722 EXPECT_EQ(id, ids_to_check[0]);
1723 EXPECT_EQ(1u, components.count(id));
1724
sorin7cff6e52017-05-17 16:37:231725 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031726 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101727 package.hash_sha256 =
1728 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031729 package.fingerprint = "1";
sorin30474f02017-04-27 00:45:481730
sorin7cff6e52017-05-17 16:37:231731 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481732 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171733 result.status = "ok";
sorin9797aba2015-04-17 17:15:031734 result.crx_urls.push_back(GURL("http://localhost/download/"));
1735 result.manifest.version = "1.0";
1736 result.manifest.browser_min_version = "11.0.1.0";
1737 result.manifest.packages.push_back(package);
sorin30474f02017-04-27 00:45:481738
1739 auto& component = components.at(id);
1740 component->SetParseResult(result);
sorin9797aba2015-04-17 17:15:031741 } else if (num_call == 2) {
1742 /*
Sorin Jianua8926bf2018-03-09 21:02:531743 Mock the following response:
sorin9797aba2015-04-17 17:15:031744 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281745 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031746 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1747 <updatecheck status='ok'>
1748 <urls>
1749 <url codebase='http://localhost/download/'/>
1750 <url codebasediff='http://localhost/download/'/>
1751 </urls>
1752 <manifest version='2.0' prodversionmin='11.0.1.0'>
1753 <packages>
1754 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1755 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101756 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1757 0ecde26c262bad942b112990'
1758 fp='22'
1759 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261760 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031761 </packages>
1762 </manifest>
1763 </updatecheck>
1764 </app>
1765 </response>
1766 */
sorin30474f02017-04-27 00:45:481767 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1768 EXPECT_EQ(id, ids_to_check[0]);
1769 EXPECT_EQ(1u, components.count(id));
1770
sorin7cff6e52017-05-17 16:37:231771 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031772 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1773 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101774 package.hash_sha256 =
1775 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1776 package.hashdiff_sha256 =
1777 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031778 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:481779
sorin7cff6e52017-05-17 16:37:231780 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481781 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171782 result.status = "ok";
sorin9797aba2015-04-17 17:15:031783 result.crx_urls.push_back(GURL("http://localhost/download/"));
1784 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1785 result.manifest.version = "2.0";
1786 result.manifest.browser_min_version = "11.0.1.0";
1787 result.manifest.packages.push_back(package);
sorin30474f02017-04-27 00:45:481788
1789 auto& component = components.at(id);
1790 component->SetParseResult(result);
sorin9797aba2015-04-17 17:15:031791 } else {
1792 NOTREACHED();
1793 }
1794
1795 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:171796 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin9797aba2015-04-17 17:15:031797 }
1798 };
1799
Sorin Jianua8926bf2018-03-09 21:02:531800 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031801 public:
dchengd0fc6aa92016-04-22 18:03:121802 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031803 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211804 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531805 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031806 }
1807
Sorin Jianua8926bf2018-03-09 21:02:531808 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031809
sorin30474f02017-04-27 00:45:481810 private:
sorin9797aba2015-04-17 17:15:031811 void DoStartDownload(const GURL& url) override {
1812 DownloadMetrics download_metrics;
1813 FilePath path;
1814 Result result;
1815 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1816 download_metrics.url = url;
1817 download_metrics.downloader = DownloadMetrics::kNone;
1818 download_metrics.error = 0;
1819 download_metrics.downloaded_bytes = 53638;
1820 download_metrics.total_bytes = 53638;
1821 download_metrics.download_time_ms = 2000;
1822
1823 EXPECT_TRUE(MakeTestFile(
1824 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1825
1826 result.error = 0;
1827 result.response = path;
1828 result.downloaded_bytes = 53638;
1829 result.total_bytes = 53638;
1830 } else if (url.path() ==
1831 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1832 // A download error is injected on this execution path.
1833 download_metrics.url = url;
1834 download_metrics.downloader = DownloadMetrics::kNone;
1835 download_metrics.error = -1;
1836 download_metrics.downloaded_bytes = 0;
1837 download_metrics.total_bytes = 2105;
1838 download_metrics.download_time_ms = 1000;
1839
Sorin Jianu52de5fa2017-10-09 23:19:331840 // The response must not include a file path in the case of errors.
sorin9797aba2015-04-17 17:15:031841 result.error = -1;
sorin9797aba2015-04-17 17:15:031842 result.downloaded_bytes = 0;
1843 result.total_bytes = 2105;
1844 } else if (url.path() ==
1845 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
1846 download_metrics.url = url;
1847 download_metrics.downloader = DownloadMetrics::kNone;
1848 download_metrics.error = 0;
1849 download_metrics.downloaded_bytes = 53855;
1850 download_metrics.total_bytes = 53855;
1851 download_metrics.download_time_ms = 1000;
1852
1853 EXPECT_TRUE(MakeTestFile(
1854 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
1855
1856 result.error = 0;
1857 result.response = path;
1858 result.downloaded_bytes = 53855;
1859 result.total_bytes = 53855;
1860 }
1861
1862 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531863 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:581864 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:031865
1866 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531867 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581868 base::Unretained(this), true, result,
1869 download_metrics));
sorin9797aba2015-04-17 17:15:031870 }
1871 };
1872
Sorin Jianua8926bf2018-03-09 21:02:531873 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031874 public:
Sorin Jianua8926bf2018-03-09 21:02:531875 explicit MockPingManager(scoped_refptr<Configurator> config)
1876 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541877
1878 protected:
Sorin Jianua8926bf2018-03-09 21:02:531879 ~MockPingManager() override {
1880 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481881 EXPECT_EQ(2u, ping_data.size());
1882 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
1883 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
1884 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
1885 EXPECT_EQ(0, ping_data[0].error_category);
1886 EXPECT_EQ(0, ping_data[0].error_code);
1887 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1888 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
1889 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
1890 EXPECT_EQ(0, ping_data[1].error_category);
1891 EXPECT_EQ(0, ping_data[1].error_code);
1892 EXPECT_TRUE(ping_data[1].diff_update_failed);
1893 EXPECT_EQ(1, ping_data[1].diff_error_category); // kNetworkError.
1894 EXPECT_EQ(-1, ping_data[1].diff_error_code);
sorin9797aba2015-04-17 17:15:031895 }
1896 };
1897
sorin30474f02017-04-27 00:45:481898 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431899 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531900 config(), base::MakeRefCounted<MockPingManager>(config()),
1901 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031902
1903 MockObserver observer;
1904 {
1905 InSequence seq;
1906 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1907 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1908 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1909 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1910 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481911 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1912 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031913 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1914 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1915 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1916 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1917
1918 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1919 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1920 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1921 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1922 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481923 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1924 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031925 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1926 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1927 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1928 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1929 }
1930
1931 update_client->AddObserver(&observer);
1932
sorin30474f02017-04-27 00:45:481933 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031934
1935 {
1936 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531937 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271938 false,
Sorin Jianua8926bf2018-03-09 21:02:531939 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171940 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031941 runloop.Run();
1942 }
1943
1944 {
1945 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531946 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271947 false,
Sorin Jianua8926bf2018-03-09 21:02:531948 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171949 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031950 runloop.Run();
1951 }
1952
1953 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:091954}
1955
1956// Tests the queuing of update checks. In this scenario, two update checks are
1957// done for one CRX. The second update check call is queued up and will run
1958// after the first check has completed. The CRX has no updates.
1959TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
Sorin Jianua8926bf2018-03-09 21:02:531960 class DataCallbackMock {
sorin7c717622015-05-26 19:59:091961 public:
Sorin Jianu7c22795b2018-04-26 22:16:521962 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1963 const std::vector<std::string>& ids) {
1964 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1965 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:241966 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521967 crx->version = base::Version("0.9");
1968 crx->installer = base::MakeRefCounted<TestInstaller>();
1969 std::vector<std::unique_ptr<CrxComponent>> component;
1970 component.push_back(std::move(crx));
1971 return component;
sorin7c717622015-05-26 19:59:091972 }
1973 };
1974
Sorin Jianua8926bf2018-03-09 21:02:531975 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:091976 public:
Sorin Jianua8ef73d2017-11-02 16:55:171977 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7c717622015-05-26 19:59:091978 static int num_call = 0;
1979 ++num_call;
1980
sorin7b8650522016-11-02 18:23:411981 EXPECT_EQ(Error::NONE, error);
sorin7c717622015-05-26 19:59:091982
1983 if (num_call == 2)
Sorin Jianua8ef73d2017-11-02 16:55:171984 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:091985 }
1986 };
1987
Sorin Jianua8926bf2018-03-09 21:02:531988 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:091989 public:
dchengd0fc6aa92016-04-22 18:03:121990 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421991 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491992 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531993 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:091994 }
1995
Sorin Jianud69d4372018-02-07 19:44:221996 void CheckForUpdates(const std::string& session_id,
1997 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171998 const IdToComponentPtrMap& components,
1999 const std::string& additional_attributes,
2000 bool enabled_component_updates,
2001 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222002 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482003 EXPECT_TRUE(enabled_component_updates);
2004 EXPECT_EQ(1u, ids_to_check.size());
2005 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2006 EXPECT_EQ(id, ids_to_check.front());
2007 EXPECT_EQ(1u, components.count(id));
2008
2009 auto& component = components.at(id);
2010
Sorin Jianub41a592a2018-03-02 16:30:272011 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:482012
sorin7cff6e52017-05-17 16:37:232013 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482014 result.extension_id = id;
2015 result.status = "noupdate";
2016 component->SetParseResult(result);
2017
sorin7c717622015-05-26 19:59:092018 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:172019 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin7c717622015-05-26 19:59:092020 }
2021 };
2022
Sorin Jianua8926bf2018-03-09 21:02:532023 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092024 public:
dchengd0fc6aa92016-04-22 18:03:122025 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092026 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212027 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532028 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092029 }
2030
Sorin Jianua8926bf2018-03-09 21:02:532031 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092032
sorin30474f02017-04-27 00:45:482033 private:
sorin7c717622015-05-26 19:59:092034 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2035 };
2036
Sorin Jianua8926bf2018-03-09 21:02:532037 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092038 public:
Sorin Jianua8926bf2018-03-09 21:02:532039 explicit MockPingManager(scoped_refptr<Configurator> config)
2040 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542041
2042 protected:
Sorin Jianua8926bf2018-03-09 21:02:532043 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin7c717622015-05-26 19:59:092044 };
2045
sorin30474f02017-04-27 00:45:482046 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432047 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532048 config(), base::MakeRefCounted<MockPingManager>(config()),
2049 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:092050
2051 MockObserver observer;
2052 InSequence seq;
2053 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2054 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2055 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2056 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2057 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2058 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2059 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2060 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2061
2062 update_client->AddObserver(&observer);
2063
sorin30474f02017-04-27 00:45:482064 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin7c717622015-05-26 19:59:092065 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532066 ids, base::BindOnce(&DataCallbackMock::Callback), false,
2067 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092068 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532069 ids, base::BindOnce(&DataCallbackMock::Callback), false,
2070 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092071
2072 RunThreads();
2073
2074 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:092075}
2076
2077// Tests the install of one CRX.
2078TEST_F(UpdateClientTest, OneCrxInstall) {
Sorin Jianua8926bf2018-03-09 21:02:532079 class DataCallbackMock {
sorin7c717622015-05-26 19:59:092080 public:
Sorin Jianu7c22795b2018-04-26 22:16:522081 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2082 const std::vector<std::string>& ids) {
2083 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2084 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242085 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522086 crx->version = base::Version("0.0");
2087 crx->installer = base::MakeRefCounted<TestInstaller>();
sorin7c717622015-05-26 19:59:092088
Sorin Jianu7c22795b2018-04-26 22:16:522089 std::vector<std::unique_ptr<CrxComponent>> component;
2090 component.push_back(std::move(crx));
2091 return component;
sorin7c717622015-05-26 19:59:092092 }
2093 };
2094
Sorin Jianua8926bf2018-03-09 21:02:532095 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:092096 public:
Sorin Jianua8ef73d2017-11-02 16:55:172097 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:412098 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172099 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:092100 }
2101 };
2102
Sorin Jianua8926bf2018-03-09 21:02:532103 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:092104 public:
dchengd0fc6aa92016-04-22 18:03:122105 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422106 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492107 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532108 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:092109 }
2110
Sorin Jianud69d4372018-02-07 19:44:222111 void CheckForUpdates(const std::string& session_id,
2112 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172113 const IdToComponentPtrMap& components,
2114 const std::string& additional_attributes,
2115 bool enabled_component_updates,
2116 UpdateCheckCallback update_check_callback) override {
sorin7c717622015-05-26 19:59:092117 /*
Sorin Jianua8926bf2018-03-09 21:02:532118 Mock the following response:
sorin7c717622015-05-26 19:59:092119
2120 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282121 <response protocol='3.1'>
sorin7c717622015-05-26 19:59:092122 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2123 <updatecheck status='ok'>
2124 <urls>
2125 <url codebase='http://localhost/download/'/>
2126 </urls>
2127 <manifest version='1.0' prodversionmin='11.0.1.0'>
2128 <packages>
sorin74e70672016-02-03 03:13:102129 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
2130 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
2131 7c9b12cb7cc067667bde87'/>
sorin7c717622015-05-26 19:59:092132 </packages>
2133 </manifest>
2134 </updatecheck>
2135 </app>
2136 </response>
2137 */
Sorin Jianud69d4372018-02-07 19:44:222138 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482139 EXPECT_TRUE(enabled_component_updates);
2140 EXPECT_EQ(1u, ids_to_check.size());
2141
2142 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2143 EXPECT_EQ(id, ids_to_check[0]);
2144 EXPECT_EQ(1u, components.count(id));
2145
sorin7cff6e52017-05-17 16:37:232146 ProtocolParser::Result::Manifest::Package package;
sorin7c717622015-05-26 19:59:092147 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:102148 package.hash_sha256 =
2149 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin30474f02017-04-27 00:45:482150
sorin7cff6e52017-05-17 16:37:232151 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482152 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:172153 result.status = "ok";
sorin7c717622015-05-26 19:59:092154 result.crx_urls.push_back(GURL("http://localhost/download/"));
2155 result.manifest.version = "1.0";
2156 result.manifest.browser_min_version = "11.0.1.0";
2157 result.manifest.packages.push_back(package);
2158
sorin30474f02017-04-27 00:45:482159 auto& component = components.at(id);
2160 component->SetParseResult(result);
2161
2162 // Verify that calling Install sets ondemand.
Sorin Jianub41a592a2018-03-02 16:30:272163 EXPECT_TRUE(component->is_foreground());
sorin7c717622015-05-26 19:59:092164
2165 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:172166 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin7c717622015-05-26 19:59:092167 }
2168 };
2169
Sorin Jianua8926bf2018-03-09 21:02:532170 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092171 public:
dchengd0fc6aa92016-04-22 18:03:122172 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092173 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212174 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532175 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092176 }
2177
Sorin Jianua8926bf2018-03-09 21:02:532178 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092179
sorin30474f02017-04-27 00:45:482180 private:
sorin7c717622015-05-26 19:59:092181 void DoStartDownload(const GURL& url) override {
2182 DownloadMetrics download_metrics;
2183 FilePath path;
2184 Result result;
2185 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
2186 download_metrics.url = url;
2187 download_metrics.downloader = DownloadMetrics::kNone;
2188 download_metrics.error = 0;
2189 download_metrics.downloaded_bytes = 1843;
2190 download_metrics.total_bytes = 1843;
2191 download_metrics.download_time_ms = 1000;
2192
2193 EXPECT_TRUE(MakeTestFile(
2194 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
2195
2196 result.error = 0;
2197 result.response = path;
2198 result.downloaded_bytes = 1843;
2199 result.total_bytes = 1843;
2200 } else {
2201 NOTREACHED();
2202 }
2203
2204 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532205 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:582206 base::Unretained(this), result));
sorin7c717622015-05-26 19:59:092207
2208 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532209 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582210 base::Unretained(this), true, result,
2211 download_metrics));
sorin7c717622015-05-26 19:59:092212 }
2213 };
2214
Sorin Jianua8926bf2018-03-09 21:02:532215 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092216 public:
Sorin Jianua8926bf2018-03-09 21:02:532217 explicit MockPingManager(scoped_refptr<Configurator> config)
2218 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542219
2220 protected:
Sorin Jianua8926bf2018-03-09 21:02:532221 ~MockPingManager() override {
2222 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482223 EXPECT_EQ(1u, ping_data.size());
2224 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
2225 EXPECT_EQ(base::Version("0.0"), ping_data[0].previous_version);
2226 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
2227 EXPECT_EQ(0, ping_data[0].error_category);
2228 EXPECT_EQ(0, ping_data[0].error_code);
sorin7c717622015-05-26 19:59:092229 }
2230 };
2231
sorin30474f02017-04-27 00:45:482232 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432233 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532234 config(), base::MakeRefCounted<MockPingManager>(config()),
2235 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:092236
2237 MockObserver observer;
sorin7c717622015-05-26 19:59:092238 InSequence seq;
2239 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2240 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2241 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2242 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2243 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482244 "jebgalgnebhfojomionfpkfelancnnkf"))
2245 .Times(AtLeast(1));
sorin7c717622015-05-26 19:59:092246 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2247 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2248 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2249 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2250
2251 update_client->AddObserver(&observer);
2252
2253 update_client->Install(
2254 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532255 base::BindOnce(&DataCallbackMock::Callback),
2256 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092257
2258 RunThreads();
2259
2260 update_client->RemoveObserver(&observer);
sorin9797aba2015-04-17 17:15:032261}
2262
Sorin Jianucb4431a2018-04-30 20:59:242263// Tests the install of one CRX when no component data is provided. This
2264// results in an install error.
2265TEST_F(UpdateClientTest, OneCrxInstallNoCrxComponentData) {
2266 class DataCallbackMock {
2267 public:
2268 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2269 const std::vector<std::string>& ids) {
2270 std::vector<std::unique_ptr<CrxComponent>> component;
2271 component.push_back(nullptr);
2272 return component;
2273 }
2274 };
2275
2276 class CompletionCallbackMock {
2277 public:
2278 static void Callback(base::OnceClosure quit_closure, Error error) {
2279 EXPECT_EQ(Error::NONE, error);
2280 std::move(quit_closure).Run();
2281 }
2282 };
2283
2284 class MockUpdateChecker : public UpdateChecker {
2285 public:
2286 static std::unique_ptr<UpdateChecker> Create(
2287 scoped_refptr<Configurator> config,
2288 PersistedData* metadata) {
2289 return std::make_unique<MockUpdateChecker>();
2290 }
2291
2292 void CheckForUpdates(const std::string& session_id,
2293 const std::vector<std::string>& ids_to_check,
2294 const IdToComponentPtrMap& components,
2295 const std::string& additional_attributes,
2296 bool enabled_component_updates,
2297 UpdateCheckCallback update_check_callback) override {
2298 NOTREACHED();
2299 }
2300 };
2301
2302 class MockCrxDownloader : public CrxDownloader {
2303 public:
2304 static std::unique_ptr<CrxDownloader> Create(
2305 bool is_background_download,
2306 scoped_refptr<net::URLRequestContextGetter> context_getter) {
2307 return std::make_unique<MockCrxDownloader>();
2308 }
2309
2310 MockCrxDownloader() : CrxDownloader(nullptr) {}
2311
2312 private:
2313 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
2314 };
2315
2316 class MockPingManager : public MockPingManagerImpl {
2317 public:
2318 explicit MockPingManager(scoped_refptr<Configurator> config)
2319 : MockPingManagerImpl(config) {}
2320
2321 protected:
2322 ~MockPingManager() override {
2323 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
2324 }
2325 };
2326
2327 scoped_refptr<UpdateClient> update_client =
2328 base::MakeRefCounted<UpdateClientImpl>(
2329 config(), base::MakeRefCounted<MockPingManager>(config()),
2330 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
2331
2332 MockObserver observer;
2333 InSequence seq;
2334 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
2335 "jebgalgnebhfojomionfpkfelancnnkf"))
2336 .Times(1);
2337
2338 update_client->AddObserver(&observer);
2339
2340 update_client->Install(
2341 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2342 base::BindOnce(&DataCallbackMock::Callback),
2343 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
2344
2345 RunThreads();
2346
2347 update_client->RemoveObserver(&observer);
2348}
2349
sorin08d153c2015-10-30 00:04:202350// Tests that overlapping installs of the same CRX result in an error.
2351TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
Sorin Jianua8926bf2018-03-09 21:02:532352 class DataCallbackMock {
sorin08d153c2015-10-30 00:04:202353 public:
Sorin Jianu7c22795b2018-04-26 22:16:522354 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2355 const std::vector<std::string>& ids) {
2356 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2357 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242358 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522359 crx->version = base::Version("0.0");
2360 crx->installer = base::MakeRefCounted<TestInstaller>();
2361 std::vector<std::unique_ptr<CrxComponent>> component;
2362 component.push_back(std::move(crx));
2363 return component;
sorin08d153c2015-10-30 00:04:202364 }
2365 };
2366
Sorin Jianua8926bf2018-03-09 21:02:532367 class CompletionCallbackMock {
sorin08d153c2015-10-30 00:04:202368 public:
Sorin Jianua8ef73d2017-11-02 16:55:172369 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin08d153c2015-10-30 00:04:202370 static int num_call = 0;
2371 ++num_call;
2372
2373 EXPECT_LE(num_call, 2);
2374
2375 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412376 EXPECT_EQ(Error::UPDATE_IN_PROGRESS, error);
sorin08d153c2015-10-30 00:04:202377 return;
2378 }
2379 if (num_call == 2) {
sorin7b8650522016-11-02 18:23:412380 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172381 std::move(quit_closure).Run();
sorin08d153c2015-10-30 00:04:202382 }
2383 }
2384 };
2385
Sorin Jianua8926bf2018-03-09 21:02:532386 class MockUpdateChecker : public UpdateChecker {
sorin08d153c2015-10-30 00:04:202387 public:
dchengd0fc6aa92016-04-22 18:03:122388 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422389 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492390 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532391 return std::make_unique<MockUpdateChecker>();
sorin08d153c2015-10-30 00:04:202392 }
2393
Sorin Jianud69d4372018-02-07 19:44:222394 void CheckForUpdates(const std::string& session_id,
2395 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172396 const IdToComponentPtrMap& components,
2397 const std::string& additional_attributes,
2398 bool enabled_component_updates,
2399 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222400 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482401 EXPECT_TRUE(enabled_component_updates);
2402 EXPECT_EQ(1u, ids_to_check.size());
2403 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2404 EXPECT_EQ(id, ids_to_check.front());
2405 EXPECT_EQ(1u, components.count(id));
2406
sorin7cff6e52017-05-17 16:37:232407 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482408 result.extension_id = id;
2409 result.status = "noupdate";
2410
2411 auto& component = components.at(id);
2412 component->SetParseResult(result);
2413
Sorin Jianub41a592a2018-03-02 16:30:272414 // Verify that calling Install sets |is_foreground| for the component.
2415 EXPECT_TRUE(component->is_foreground());
sorin30474f02017-04-27 00:45:482416
sorin08d153c2015-10-30 00:04:202417 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:172418 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorin08d153c2015-10-30 00:04:202419 }
2420 };
2421
Sorin Jianua8926bf2018-03-09 21:02:532422 class MockCrxDownloader : public CrxDownloader {
sorin08d153c2015-10-30 00:04:202423 public:
dchengd0fc6aa92016-04-22 18:03:122424 static std::unique_ptr<CrxDownloader> Create(
sorin08d153c2015-10-30 00:04:202425 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212426 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532427 return std::make_unique<MockCrxDownloader>();
sorin08d153c2015-10-30 00:04:202428 }
2429
Sorin Jianua8926bf2018-03-09 21:02:532430 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin08d153c2015-10-30 00:04:202431
sorin30474f02017-04-27 00:45:482432 private:
sorin08d153c2015-10-30 00:04:202433 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2434 };
2435
Sorin Jianua8926bf2018-03-09 21:02:532436 class MockPingManager : public MockPingManagerImpl {
sorin08d153c2015-10-30 00:04:202437 public:
Sorin Jianua8926bf2018-03-09 21:02:532438 explicit MockPingManager(scoped_refptr<Configurator> config)
2439 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542440
2441 protected:
Sorin Jianua8926bf2018-03-09 21:02:532442 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin08d153c2015-10-30 00:04:202443 };
2444
sorin30474f02017-04-27 00:45:482445 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432446 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532447 config(), base::MakeRefCounted<MockPingManager>(config()),
2448 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin08d153c2015-10-30 00:04:202449
2450 MockObserver observer;
sorin08d153c2015-10-30 00:04:202451 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2452 "jebgalgnebhfojomionfpkfelancnnkf"))
2453 .Times(1);
2454 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2455 "jebgalgnebhfojomionfpkfelancnnkf"))
2456 .Times(1);
2457
2458 update_client->AddObserver(&observer);
2459
2460 update_client->Install(
2461 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532462 base::BindOnce(&DataCallbackMock::Callback),
2463 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:202464
2465 update_client->Install(
2466 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532467 base::BindOnce(&DataCallbackMock::Callback),
2468 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:202469
2470 RunThreads();
2471
2472 update_client->RemoveObserver(&observer);
sorin08d153c2015-10-30 00:04:202473}
2474
sorin30474f02017-04-27 00:45:482475// Tests that UpdateClient::Update returns Error::INVALID_ARGUMENT when
2476// the |ids| parameter is empty.
asargente90363b2015-09-09 22:40:072477TEST_F(UpdateClientTest, EmptyIdList) {
Sorin Jianua8926bf2018-03-09 21:02:532478 class DataCallbackMock {
asargente90363b2015-09-09 22:40:072479 public:
Sorin Jianu7c22795b2018-04-26 22:16:522480 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2481 const std::vector<std::string>& ids) {
2482 return {};
2483 }
asargente90363b2015-09-09 22:40:072484 };
2485
Sorin Jianua8926bf2018-03-09 21:02:532486 class CompletionCallbackMock {
asargente90363b2015-09-09 22:40:072487 public:
Sorin Jianua8ef73d2017-11-02 16:55:172488 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin30474f02017-04-27 00:45:482489 DCHECK_EQ(Error::INVALID_ARGUMENT, error);
Sorin Jianua8ef73d2017-11-02 16:55:172490 std::move(quit_closure).Run();
asargente90363b2015-09-09 22:40:072491 }
2492 };
sorin30474f02017-04-27 00:45:482493
Sorin Jianua8926bf2018-03-09 21:02:532494 class MockUpdateChecker : public UpdateChecker {
asargente90363b2015-09-09 22:40:072495 public:
dchengd0fc6aa92016-04-22 18:03:122496 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422497 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492498 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532499 return std::make_unique<MockUpdateChecker>();
asargente90363b2015-09-09 22:40:072500 }
2501
Sorin Jianud69d4372018-02-07 19:44:222502 void CheckForUpdates(const std::string& session_id,
2503 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172504 const IdToComponentPtrMap& components,
2505 const std::string& additional_attributes,
2506 bool enabled_component_updates,
Sorin Jianud69d4372018-02-07 19:44:222507 UpdateCheckCallback update_check_callback) override {
2508 NOTREACHED();
2509 }
asargente90363b2015-09-09 22:40:072510 };
2511
Sorin Jianua8926bf2018-03-09 21:02:532512 class MockCrxDownloader : public CrxDownloader {
asargente90363b2015-09-09 22:40:072513 public:
dchengd0fc6aa92016-04-22 18:03:122514 static std::unique_ptr<CrxDownloader> Create(
asargente90363b2015-09-09 22:40:072515 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212516 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532517 return std::make_unique<MockCrxDownloader>();
asargente90363b2015-09-09 22:40:072518 }
2519
Sorin Jianua8926bf2018-03-09 21:02:532520 MockCrxDownloader() : CrxDownloader(nullptr) {}
asargente90363b2015-09-09 22:40:072521
sorin30474f02017-04-27 00:45:482522 private:
asargente90363b2015-09-09 22:40:072523 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2524 };
2525
Sorin Jianua8926bf2018-03-09 21:02:532526 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu560d5022018-02-12 23:11:542527 public:
Sorin Jianua8926bf2018-03-09 21:02:532528 explicit MockPingManager(scoped_refptr<Configurator> config)
2529 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542530
2531 protected:
Sorin Jianua8926bf2018-03-09 21:02:532532 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
Sorin Jianu560d5022018-02-12 23:11:542533 };
2534
sorin30474f02017-04-27 00:45:482535 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432536 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532537 config(), base::MakeRefCounted<MockPingManager>(config()),
2538 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
asargente90363b2015-09-09 22:40:072539
sorin30474f02017-04-27 00:45:482540 const std::vector<std::string> empty_id_list;
asargente90363b2015-09-09 22:40:072541 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532542 empty_id_list, base::BindOnce(&DataCallbackMock::Callback), false,
2543 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin30474f02017-04-27 00:45:482544 RunThreads();
asargente90363b2015-09-09 22:40:072545}
2546
sorin805aa03112016-01-14 23:01:312547TEST_F(UpdateClientTest, SendUninstallPing) {
Sorin Jianua8926bf2018-03-09 21:02:532548 class CompletionCallbackMock {
sorin8037ac8c2017-04-19 16:28:002549 public:
Sorin Jianua8ef73d2017-11-02 16:55:172550 static void Callback(base::OnceClosure quit_closure, Error error) {
2551 std::move(quit_closure).Run();
sorin8037ac8c2017-04-19 16:28:002552 }
2553 };
2554
Sorin Jianua8926bf2018-03-09 21:02:532555 class MockUpdateChecker : public UpdateChecker {
sorin805aa03112016-01-14 23:01:312556 public:
dchengd0fc6aa92016-04-22 18:03:122557 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422558 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492559 PersistedData* metadata) {
sorin805aa03112016-01-14 23:01:312560 return nullptr;
2561 }
2562
Sorin Jianud69d4372018-02-07 19:44:222563 void CheckForUpdates(const std::string& session_id,
2564 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172565 const IdToComponentPtrMap& components,
2566 const std::string& additional_attributes,
2567 bool enabled_component_updates,
Sorin Jianud69d4372018-02-07 19:44:222568 UpdateCheckCallback update_check_callback) override {
2569 NOTREACHED();
2570 }
sorin805aa03112016-01-14 23:01:312571 };
2572
Sorin Jianua8926bf2018-03-09 21:02:532573 class MockCrxDownloader : public CrxDownloader {
sorin805aa03112016-01-14 23:01:312574 public:
dchengd0fc6aa92016-04-22 18:03:122575 static std::unique_ptr<CrxDownloader> Create(
sorin805aa03112016-01-14 23:01:312576 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212577 scoped_refptr<net::URLRequestContextGetter> context_getter) {
sorin805aa03112016-01-14 23:01:312578 return nullptr;
2579 }
2580
2581 private:
Sorin Jianua8926bf2018-03-09 21:02:532582 MockCrxDownloader() : CrxDownloader(nullptr) {}
2583 ~MockCrxDownloader() override {}
sorin805aa03112016-01-14 23:01:312584
2585 void DoStartDownload(const GURL& url) override {}
2586 };
2587
Sorin Jianua8926bf2018-03-09 21:02:532588 class MockPingManager : public MockPingManagerImpl {
sorin805aa03112016-01-14 23:01:312589 public:
Sorin Jianua8926bf2018-03-09 21:02:532590 explicit MockPingManager(scoped_refptr<Configurator> config)
2591 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542592
2593 protected:
Sorin Jianua8926bf2018-03-09 21:02:532594 ~MockPingManager() override {
2595 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482596 EXPECT_EQ(1u, ping_data.size());
2597 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
Minh X. Nguyen01d3586d2018-01-03 21:53:392598 EXPECT_EQ(base::Version("1.2.3.4"), ping_data[0].previous_version);
2599 EXPECT_EQ(base::Version("0"), ping_data[0].next_version);
sorin30474f02017-04-27 00:45:482600 EXPECT_EQ(10, ping_data[0].extra_code1);
sorin805aa03112016-01-14 23:01:312601 }
2602 };
2603
sorin30474f02017-04-27 00:45:482604 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432605 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532606 config(), base::MakeRefCounted<MockPingManager>(config()),
2607 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin805aa03112016-01-14 23:01:312608
sorin8037ac8c2017-04-19 16:28:002609 update_client->SendUninstallPing(
Minh X. Nguyen01d3586d2018-01-03 21:53:392610 "jebgalgnebhfojomionfpkfelancnnkf", base::Version("1.2.3.4"), 10,
Sorin Jianua8926bf2018-03-09 21:02:532611 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin8037ac8c2017-04-19 16:28:002612
2613 RunThreads();
sorin805aa03112016-01-14 23:01:312614}
2615
sorinfccbf2d2016-04-04 20:34:342616TEST_F(UpdateClientTest, RetryAfter) {
Sorin Jianua8926bf2018-03-09 21:02:532617 class DataCallbackMock {
sorinfccbf2d2016-04-04 20:34:342618 public:
Sorin Jianu7c22795b2018-04-26 22:16:522619 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2620 const std::vector<std::string>& ids) {
2621 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2622 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242623 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522624 crx->version = base::Version("0.9");
2625 crx->installer = base::MakeRefCounted<TestInstaller>();
2626 std::vector<std::unique_ptr<CrxComponent>> component;
2627 component.push_back(std::move(crx));
2628 return component;
sorinfccbf2d2016-04-04 20:34:342629 }
2630 };
2631
Sorin Jianua8926bf2018-03-09 21:02:532632 class CompletionCallbackMock {
sorinfccbf2d2016-04-04 20:34:342633 public:
Sorin Jianua8ef73d2017-11-02 16:55:172634 static void Callback(base::OnceClosure quit_closure, Error error) {
sorinfccbf2d2016-04-04 20:34:342635 static int num_call = 0;
2636 ++num_call;
2637
2638 EXPECT_LE(num_call, 4);
2639
2640 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412641 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342642 } else if (num_call == 2) {
2643 // This request is throttled since the update engine received a
2644 // positive |retry_after_sec| value in the update check response.
sorin7b8650522016-11-02 18:23:412645 EXPECT_EQ(Error::RETRY_LATER, error);
sorinfccbf2d2016-04-04 20:34:342646 } else if (num_call == 3) {
2647 // This request is a foreground Install, which is never throttled.
2648 // The update engine received a |retry_after_sec| value of 0, which
2649 // resets the throttling.
sorin7b8650522016-11-02 18:23:412650 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342651 } else if (num_call == 4) {
2652 // This request succeeds since there is no throttling in effect.
sorin7b8650522016-11-02 18:23:412653 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342654 }
2655
Sorin Jianua8ef73d2017-11-02 16:55:172656 std::move(quit_closure).Run();
sorinfccbf2d2016-04-04 20:34:342657 }
2658 };
2659
Sorin Jianua8926bf2018-03-09 21:02:532660 class MockUpdateChecker : public UpdateChecker {
sorinfccbf2d2016-04-04 20:34:342661 public:
dchengd0fc6aa92016-04-22 18:03:122662 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422663 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492664 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532665 return std::make_unique<MockUpdateChecker>();
sorinfccbf2d2016-04-04 20:34:342666 }
2667
Sorin Jianud69d4372018-02-07 19:44:222668 void CheckForUpdates(const std::string& session_id,
2669 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172670 const IdToComponentPtrMap& components,
2671 const std::string& additional_attributes,
2672 bool enabled_component_updates,
2673 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222674 EXPECT_FALSE(session_id.empty());
2675
sorinfccbf2d2016-04-04 20:34:342676 static int num_call = 0;
2677 ++num_call;
2678
2679 EXPECT_LE(num_call, 3);
2680
2681 int retry_after_sec(0);
2682 if (num_call == 1) {
2683 // Throttle the next call.
2684 retry_after_sec = 60 * 60; // 1 hour.
2685 }
2686
sorin30474f02017-04-27 00:45:482687 EXPECT_EQ(1u, ids_to_check.size());
2688 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2689 EXPECT_EQ(id, ids_to_check.front());
2690 EXPECT_EQ(1u, components.count(id));
2691
2692 auto& component = components.at(id);
2693
sorin7cff6e52017-05-17 16:37:232694 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482695 result.extension_id = id;
2696 result.status = "noupdate";
2697 component->SetParseResult(result);
2698
sorinfccbf2d2016-04-04 20:34:342699 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:172700 FROM_HERE,
2701 base::BindOnce(std::move(update_check_callback), 0, retry_after_sec));
sorinfccbf2d2016-04-04 20:34:342702 }
2703 };
2704
Sorin Jianua8926bf2018-03-09 21:02:532705 class MockCrxDownloader : public CrxDownloader {
sorinfccbf2d2016-04-04 20:34:342706 public:
dchengd0fc6aa92016-04-22 18:03:122707 static std::unique_ptr<CrxDownloader> Create(
sorinfccbf2d2016-04-04 20:34:342708 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212709 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532710 return std::make_unique<MockCrxDownloader>();
sorinfccbf2d2016-04-04 20:34:342711 }
2712
Sorin Jianua8926bf2018-03-09 21:02:532713 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorinfccbf2d2016-04-04 20:34:342714
sorin30474f02017-04-27 00:45:482715 private:
sorinfccbf2d2016-04-04 20:34:342716 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2717 };
2718
Sorin Jianua8926bf2018-03-09 21:02:532719 class MockPingManager : public MockPingManagerImpl {
sorinfccbf2d2016-04-04 20:34:342720 public:
Sorin Jianua8926bf2018-03-09 21:02:532721 explicit MockPingManager(scoped_refptr<Configurator> config)
2722 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542723
2724 protected:
Sorin Jianua8926bf2018-03-09 21:02:532725 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorinfccbf2d2016-04-04 20:34:342726 };
2727
sorin30474f02017-04-27 00:45:482728 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432729 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532730 config(), base::MakeRefCounted<MockPingManager>(config()),
2731 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorinfccbf2d2016-04-04 20:34:342732
2733 MockObserver observer;
2734
2735 InSequence seq;
2736 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2737 "jebgalgnebhfojomionfpkfelancnnkf"))
2738 .Times(1);
2739 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2740 "jebgalgnebhfojomionfpkfelancnnkf"))
2741 .Times(1);
2742 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2743 "jebgalgnebhfojomionfpkfelancnnkf"))
2744 .Times(1);
2745 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2746 "jebgalgnebhfojomionfpkfelancnnkf"))
2747 .Times(1);
2748 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2749 "jebgalgnebhfojomionfpkfelancnnkf"))
2750 .Times(1);
2751 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2752 "jebgalgnebhfojomionfpkfelancnnkf"))
2753 .Times(1);
2754
2755 update_client->AddObserver(&observer);
2756
sorin30474f02017-04-27 00:45:482757 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorinfccbf2d2016-04-04 20:34:342758 {
2759 // The engine handles this Update call but responds with a valid
2760 // |retry_after_sec|, which causes subsequent calls to fail.
2761 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532762 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272763 false,
Sorin Jianua8926bf2018-03-09 21:02:532764 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172765 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342766 runloop.Run();
2767 }
2768
2769 {
2770 // This call will result in a completion callback invoked with
2771 // Error::ERROR_UPDATE_RETRY_LATER.
2772 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532773 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272774 false,
Sorin Jianua8926bf2018-03-09 21:02:532775 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172776 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342777 runloop.Run();
2778 }
2779
2780 {
2781 // The Install call is handled, and the throttling is reset due to
2782 // the value of |retry_after_sec| in the completion callback.
2783 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:172784 update_client->Install(std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532785 base::BindOnce(&DataCallbackMock::Callback),
2786 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172787 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342788 runloop.Run();
2789 }
2790
2791 {
2792 // This call succeeds.
2793 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532794 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272795 false,
Sorin Jianua8926bf2018-03-09 21:02:532796 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172797 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342798 runloop.Run();
2799 }
2800
2801 update_client->RemoveObserver(&observer);
2802}
2803
sorine84ff702016-08-04 01:22:022804// Tests the update check for two CRXs scenario. The first component supports
2805// the group policy to enable updates, and has its updates disabled. The second
2806// component has an update. The server does not honor the "updatedisabled"
sorin30474f02017-04-27 00:45:482807// attribute and returns updates for both components. However, the update for
2808// the first component is not apply and the client responds with a
2809// (SERVICE_ERROR, UPDATE_DISABLED)
sorine84ff702016-08-04 01:22:022810TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
Sorin Jianua8926bf2018-03-09 21:02:532811 class DataCallbackMock {
sorine84ff702016-08-04 01:22:022812 public:
Sorin Jianu7c22795b2018-04-26 22:16:522813 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2814 const std::vector<std::string>& ids) {
2815 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
2816 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242817 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522818 crx1->version = base::Version("0.9");
2819 crx1->installer = base::MakeRefCounted<TestInstaller>();
2820 crx1->supports_group_policy_enable_component_updates = true;
sorine84ff702016-08-04 01:22:022821
Sorin Jianu7c22795b2018-04-26 22:16:522822 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
2823 crx2->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:242824 crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522825 crx2->version = base::Version("0.8");
2826 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorine84ff702016-08-04 01:22:022827
Sorin Jianu7c22795b2018-04-26 22:16:522828 std::vector<std::unique_ptr<CrxComponent>> component;
2829 component.push_back(std::move(crx1));
2830 component.push_back(std::move(crx2));
2831 return component;
sorine84ff702016-08-04 01:22:022832 }
2833 };
2834
Sorin Jianua8926bf2018-03-09 21:02:532835 class CompletionCallbackMock {
sorine84ff702016-08-04 01:22:022836 public:
Sorin Jianua8ef73d2017-11-02 16:55:172837 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:412838 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172839 std::move(quit_closure).Run();
sorine84ff702016-08-04 01:22:022840 }
2841 };
2842
Sorin Jianua8926bf2018-03-09 21:02:532843 class MockUpdateChecker : public UpdateChecker {
sorine84ff702016-08-04 01:22:022844 public:
2845 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422846 scoped_refptr<Configurator> config,
sorine84ff702016-08-04 01:22:022847 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532848 return std::make_unique<MockUpdateChecker>();
sorine84ff702016-08-04 01:22:022849 }
2850
Sorin Jianud69d4372018-02-07 19:44:222851 void CheckForUpdates(const std::string& session_id,
2852 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172853 const IdToComponentPtrMap& components,
2854 const std::string& additional_attributes,
2855 bool enabled_component_updates,
2856 UpdateCheckCallback update_check_callback) override {
sorine84ff702016-08-04 01:22:022857 /*
Sorin Jianua8926bf2018-03-09 21:02:532858 Mock the following response:
sorine84ff702016-08-04 01:22:022859
2860 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282861 <response protocol='3.1'>
sorine84ff702016-08-04 01:22:022862 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2863 <updatecheck status='ok'>
2864 <urls>
2865 <url codebase='http://localhost/download/'/>
2866 </urls>
2867 <manifest version='1.0' prodversionmin='11.0.1.0'>
2868 <packages>
2869 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
2870 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
2871 7c9b12cb7cc067667bde87'/>
2872 </packages>
2873 </manifest>
2874 </updatecheck>
2875 </app>
2876 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
2877 <updatecheck status='ok'>
2878 <urls>
2879 <url codebase='http://localhost/download/'/>
2880 </urls>
2881 <manifest version='1.0' prodversionmin='11.0.1.0'>
2882 <packages>
2883 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
2884 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
2885 309f156ea6d27229c0b3f9'/>
2886 </packages>
2887 </manifest>
2888 </updatecheck>
2889 </app>
2890 </response>
2891 */
sorin590921d2016-08-11 23:48:362892
2893 // UpdateClient reads the state of |enabled_component_updates| from the
2894 // configurator instance, persists its value in the corresponding
2895 // update context, and propagates it down to each of the update actions,
2896 // and further down to the UpdateChecker instance.
Sorin Jianud69d4372018-02-07 19:44:222897 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:362898 EXPECT_FALSE(enabled_component_updates);
sorin30474f02017-04-27 00:45:482899 EXPECT_EQ(2u, ids_to_check.size());
sorine84ff702016-08-04 01:22:022900
sorin30474f02017-04-27 00:45:482901 {
2902 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2903 EXPECT_EQ(id, ids_to_check[0]);
2904 EXPECT_EQ(1u, components.count(id));
sorine84ff702016-08-04 01:22:022905
sorin7cff6e52017-05-17 16:37:232906 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:482907 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
2908 package.hash_sha256 =
2909 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorine84ff702016-08-04 01:22:022910
sorin7cff6e52017-05-17 16:37:232911 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482912 result.extension_id = id;
2913 result.status = "ok";
2914 result.crx_urls.push_back(GURL("http://localhost/download/"));
2915 result.manifest.version = "1.0";
2916 result.manifest.browser_min_version = "11.0.1.0";
2917 result.manifest.packages.push_back(package);
sorine84ff702016-08-04 01:22:022918
sorin30474f02017-04-27 00:45:482919 auto& component = components.at(id);
2920 component->SetParseResult(result);
2921 }
2922
2923 {
2924 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
2925 EXPECT_EQ(id, ids_to_check[1]);
2926 EXPECT_EQ(1u, components.count(id));
2927
sorin7cff6e52017-05-17 16:37:232928 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:482929 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
2930 package.hash_sha256 =
2931 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
2932
sorin7cff6e52017-05-17 16:37:232933 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482934 result.extension_id = id;
2935 result.status = "ok";
2936 result.crx_urls.push_back(GURL("http://localhost/download/"));
2937 result.manifest.version = "1.0";
2938 result.manifest.browser_min_version = "11.0.1.0";
2939 result.manifest.packages.push_back(package);
2940
2941 auto& component = components.at(id);
2942 component->SetParseResult(result);
2943 }
sorine84ff702016-08-04 01:22:022944
2945 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:172946 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
sorine84ff702016-08-04 01:22:022947 }
2948 };
2949
Sorin Jianua8926bf2018-03-09 21:02:532950 class MockCrxDownloader : public CrxDownloader {
sorine84ff702016-08-04 01:22:022951 public:
2952 static std::unique_ptr<CrxDownloader> Create(
2953 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212954 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532955 return std::make_unique<MockCrxDownloader>();
sorine84ff702016-08-04 01:22:022956 }
2957
Sorin Jianua8926bf2018-03-09 21:02:532958 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorine84ff702016-08-04 01:22:022959
sorin30474f02017-04-27 00:45:482960 private:
sorine84ff702016-08-04 01:22:022961 void DoStartDownload(const GURL& url) override {
2962 DownloadMetrics download_metrics;
2963 FilePath path;
2964 Result result;
2965 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
2966 download_metrics.url = url;
2967 download_metrics.downloader = DownloadMetrics::kNone;
2968 download_metrics.error = 0;
2969 download_metrics.downloaded_bytes = 53638;
2970 download_metrics.total_bytes = 53638;
2971 download_metrics.download_time_ms = 2000;
2972
2973 EXPECT_TRUE(MakeTestFile(
2974 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
2975
2976 result.error = 0;
2977 result.response = path;
2978 result.downloaded_bytes = 53638;
2979 result.total_bytes = 53638;
2980 } else {
2981 NOTREACHED();
2982 }
2983
2984 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532985 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:582986 base::Unretained(this), result));
sorine84ff702016-08-04 01:22:022987
2988 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532989 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582990 base::Unretained(this), true, result,
2991 download_metrics));
sorine84ff702016-08-04 01:22:022992 }
2993 };
2994
Sorin Jianua8926bf2018-03-09 21:02:532995 class MockPingManager : public MockPingManagerImpl {
sorine84ff702016-08-04 01:22:022996 public:
Sorin Jianua8926bf2018-03-09 21:02:532997 explicit MockPingManager(scoped_refptr<Configurator> config)
2998 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542999
3000 protected:
Sorin Jianua8926bf2018-03-09 21:02:533001 ~MockPingManager() override {
3002 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:483003 EXPECT_EQ(2u, ping_data.size());
3004 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
3005 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
3006 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
3007 EXPECT_EQ(4, ping_data[0].error_category);
3008 EXPECT_EQ(2, ping_data[0].error_code);
3009 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
3010 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
3011 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
3012 EXPECT_EQ(0, ping_data[1].error_category);
3013 EXPECT_EQ(0, ping_data[1].error_code);
sorine84ff702016-08-04 01:22:023014 }
3015 };
3016
3017 // Disables updates for the components declaring support for the group policy.
3018 config()->SetEnabledComponentUpdates(false);
sorin30474f02017-04-27 00:45:483019 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433020 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533021 config(), base::MakeRefCounted<MockPingManager>(config()),
3022 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorine84ff702016-08-04 01:22:023023
3024 MockObserver observer;
3025 {
3026 InSequence seq;
3027 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3028 "jebgalgnebhfojomionfpkfelancnnkf"))
3029 .Times(1);
3030 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3031 "jebgalgnebhfojomionfpkfelancnnkf"))
3032 .Times(1);
Sorin Jianucbb10e12018-01-23 18:01:443033 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorine84ff702016-08-04 01:22:023034 "jebgalgnebhfojomionfpkfelancnnkf"))
3035 .Times(1);
3036 }
3037 {
3038 InSequence seq;
3039 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3040 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3041 .Times(1);
3042 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3043 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3044 .Times(1);
sorine84ff702016-08-04 01:22:023045 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
3046 "ihfokbkgjpifnbbojhneepfflplebdkc"))
sorin30474f02017-04-27 00:45:483047 .Times(AtLeast(1));
sorine84ff702016-08-04 01:22:023048 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
3049 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3050 .Times(1);
3051 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
3052 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3053 .Times(1);
3054 }
3055
3056 update_client->AddObserver(&observer);
3057
sorin30474f02017-04-27 00:45:483058 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
3059 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorine84ff702016-08-04 01:22:023060 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:533061 ids, base::BindOnce(&DataCallbackMock::Callback), false,
3062 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorine84ff702016-08-04 01:22:023063
3064 RunThreads();
3065
3066 update_client->RemoveObserver(&observer);
3067}
3068
sorin03ec5b72017-05-01 23:14:243069// Tests the scenario where the update check fails.
3070TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
Sorin Jianua8926bf2018-03-09 21:02:533071 class DataCallbackMock {
sorin03ec5b72017-05-01 23:14:243072 public:
Sorin Jianu7c22795b2018-04-26 22:16:523073 static std::vector<std::unique_ptr<CrxComponent>> Callback(
3074 const std::vector<std::string>& ids) {
3075 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
3076 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:243077 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523078 crx->version = base::Version("0.9");
3079 crx->installer = base::MakeRefCounted<TestInstaller>();
3080 std::vector<std::unique_ptr<CrxComponent>> component;
3081 component.push_back(std::move(crx));
3082 return component;
sorin03ec5b72017-05-01 23:14:243083 }
3084 };
3085
Sorin Jianua8926bf2018-03-09 21:02:533086 class CompletionCallbackMock {
sorin03ec5b72017-05-01 23:14:243087 public:
Sorin Jianua8ef73d2017-11-02 16:55:173088 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin03ec5b72017-05-01 23:14:243089 EXPECT_EQ(Error::UPDATE_CHECK_ERROR, error);
Sorin Jianua8ef73d2017-11-02 16:55:173090 std::move(quit_closure).Run();
sorin03ec5b72017-05-01 23:14:243091 }
3092 };
3093
Sorin Jianua8926bf2018-03-09 21:02:533094 class MockUpdateChecker : public UpdateChecker {
sorin03ec5b72017-05-01 23:14:243095 public:
3096 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423097 scoped_refptr<Configurator> config,
sorin03ec5b72017-05-01 23:14:243098 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533099 return std::make_unique<MockUpdateChecker>();
sorin03ec5b72017-05-01 23:14:243100 }
3101
Sorin Jianud69d4372018-02-07 19:44:223102 void CheckForUpdates(const std::string& session_id,
3103 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173104 const IdToComponentPtrMap& components,
3105 const std::string& additional_attributes,
3106 bool enabled_component_updates,
3107 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223108 EXPECT_FALSE(session_id.empty());
sorin03ec5b72017-05-01 23:14:243109 EXPECT_TRUE(enabled_component_updates);
3110 EXPECT_EQ(1u, ids_to_check.size());
3111 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3112 EXPECT_EQ(id, ids_to_check.front());
3113 EXPECT_EQ(1u, components.count(id));
Sorin Jianuafcb70dd2018-05-16 20:14:153114 constexpr int update_check_error = -1;
3115 components.at(id)->set_update_check_error(update_check_error);
sorin03ec5b72017-05-01 23:14:243116 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuafcb70dd2018-05-16 20:14:153117 FROM_HERE, base::BindOnce(std::move(update_check_callback),
3118 update_check_error, 0));
sorin03ec5b72017-05-01 23:14:243119 }
3120 };
3121
Sorin Jianua8926bf2018-03-09 21:02:533122 class MockCrxDownloader : public CrxDownloader {
sorin03ec5b72017-05-01 23:14:243123 public:
3124 static std::unique_ptr<CrxDownloader> Create(
3125 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213126 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533127 return std::make_unique<MockCrxDownloader>();
sorin03ec5b72017-05-01 23:14:243128 }
3129
Sorin Jianua8926bf2018-03-09 21:02:533130 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin03ec5b72017-05-01 23:14:243131
3132 private:
3133 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3134 };
3135
Sorin Jianua8926bf2018-03-09 21:02:533136 class MockPingManager : public MockPingManagerImpl {
sorin03ec5b72017-05-01 23:14:243137 public:
Sorin Jianua8926bf2018-03-09 21:02:533138 explicit MockPingManager(scoped_refptr<Configurator> config)
3139 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543140
3141 protected:
Sorin Jianua8926bf2018-03-09 21:02:533142 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin03ec5b72017-05-01 23:14:243143 };
3144
3145 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433146 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533147 config(), base::MakeRefCounted<MockPingManager>(config()),
3148 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin03ec5b72017-05-01 23:14:243149
3150 MockObserver observer;
3151 InSequence seq;
3152 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3153 "jebgalgnebhfojomionfpkfelancnnkf"))
3154 .Times(1);
Sorin Jianucbb10e12018-01-23 18:01:443155 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorin03ec5b72017-05-01 23:14:243156 "jebgalgnebhfojomionfpkfelancnnkf"))
3157 .Times(1)
3158 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3159 CrxUpdateItem item;
3160 update_client->GetCrxUpdateState(id, &item);
3161 EXPECT_EQ(ComponentState::kUpdateError, item.state);
Sorin Jianuafcb70dd2018-05-16 20:14:153162 EXPECT_EQ(5, item.error_category);
3163 EXPECT_EQ(-1, item.error_code);
3164 EXPECT_EQ(0, item.extra_code1);
sorin03ec5b72017-05-01 23:14:243165 }));
3166
3167 update_client->AddObserver(&observer);
3168
3169 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
3170 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:533171 ids, base::BindOnce(&DataCallbackMock::Callback), false,
3172 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin03ec5b72017-05-01 23:14:243173
3174 RunThreads();
3175
3176 update_client->RemoveObserver(&observer);
3177}
3178
Sorin Jianu7b00a132017-06-19 21:56:543179#if defined(OS_WIN) // ActionRun is only implemented on Windows.
3180
Sorin Jianu4ab7c292017-06-15 18:40:213181// Tests that a run action in invoked in the CRX install scenario.
3182TEST_F(UpdateClientTest, ActionRun_Install) {
Sorin Jianua8926bf2018-03-09 21:02:533183 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:213184 public:
3185 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423186 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:213187 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533188 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:213189 }
3190
Sorin Jianud69d4372018-02-07 19:44:223191 void CheckForUpdates(const std::string& session_id,
3192 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173193 const IdToComponentPtrMap& components,
3194 const std::string& additional_attributes,
3195 bool enabled_component_updates,
3196 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:213197 /*
Sorin Jianua8926bf2018-03-09 21:02:533198 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:213199
3200 <?xml version='1.0' encoding='UTF-8'?>
3201 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:563202 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:213203 <updatecheck status='ok'>
3204 <urls>
3205 <url codebase='http://localhost/download/'/>
3206 </urls>
3207 <manifest version='1.0' prodversionmin='11.0.1.0'>
3208 <packages>
3209 <package name='runaction_test_win.crx3'
Sorin Jianue5bfb5b2017-06-20 21:30:563210 hash_sha256='89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea'/>
Sorin Jianu4ab7c292017-06-15 18:40:213211 </packages>
3212 </manifest>
3213 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:563214 <action run='ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:213215 </actions>"
3216 </updatecheck>
3217 </app>
3218 </response>
3219 */
Sorin Jianud69d4372018-02-07 19:44:223220 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:213221 EXPECT_TRUE(enabled_component_updates);
3222 EXPECT_EQ(1u, ids_to_check.size());
3223
Sorin Jianue5bfb5b2017-06-20 21:30:563224 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:213225 EXPECT_EQ(id, ids_to_check[0]);
3226 EXPECT_EQ(1u, components.count(id));
3227
3228 ProtocolParser::Result::Manifest::Package package;
3229 package.name = "runaction_test_win.crx3";
3230 package.hash_sha256 =
Sorin Jianue5bfb5b2017-06-20 21:30:563231 "89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea";
Sorin Jianu4ab7c292017-06-15 18:40:213232
3233 ProtocolParser::Result result;
3234 result.extension_id = id;
3235 result.status = "ok";
3236 result.crx_urls.push_back(GURL("http://localhost/download/"));
3237 result.manifest.version = "1.0";
3238 result.manifest.browser_min_version = "11.0.1.0";
3239 result.manifest.packages.push_back(package);
Sorin Jianue5bfb5b2017-06-20 21:30:563240 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:213241
3242 auto& component = components.at(id);
3243 component->SetParseResult(result);
3244
3245 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:173246 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:213247 }
3248 };
3249
Sorin Jianua8926bf2018-03-09 21:02:533250 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:213251 public:
3252 static std::unique_ptr<CrxDownloader> Create(
3253 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213254 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533255 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:213256 }
3257
Sorin Jianua8926bf2018-03-09 21:02:533258 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:213259
3260 private:
3261 void DoStartDownload(const GURL& url) override {
3262 DownloadMetrics download_metrics;
3263 FilePath path;
3264 Result result;
3265 if (url.path() == "/download/runaction_test_win.crx3") {
3266 download_metrics.url = url;
3267 download_metrics.downloader = DownloadMetrics::kNone;
3268 download_metrics.error = 0;
3269 download_metrics.downloaded_bytes = 1843;
3270 download_metrics.total_bytes = 1843;
3271 download_metrics.download_time_ms = 1000;
3272
3273 EXPECT_TRUE(
3274 MakeTestFile(TestFilePath("runaction_test_win.crx3"), &path));
3275
3276 result.error = 0;
3277 result.response = path;
3278 result.downloaded_bytes = 1843;
3279 result.total_bytes = 1843;
3280 } else {
3281 NOTREACHED();
3282 }
3283
3284 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533285 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:583286 base::Unretained(this), true, result,
3287 download_metrics));
Sorin Jianu4ab7c292017-06-15 18:40:213288 }
3289 };
3290
Sorin Jianua8926bf2018-03-09 21:02:533291 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:213292 public:
Sorin Jianua8926bf2018-03-09 21:02:533293 explicit MockPingManager(scoped_refptr<Configurator> config)
3294 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543295
3296 protected:
Sorin Jianua8926bf2018-03-09 21:02:533297 ~MockPingManager() override {
3298 const auto& events = MockPingManagerImpl::events();
Sorin Jianu4ab7c292017-06-15 18:40:213299 EXPECT_EQ(3u, events.size());
3300 EXPECT_STREQ(
3301 "<event eventtype=\"14\" eventresult=\"1\" downloader=\"unknown\" "
3302 "url=\"http://localhost/download/"
3303 "runaction_test_win.crx3\" downloaded=\"1843\" "
Minh X. Nguyen01d3586d2018-01-03 21:53:393304 "total=\"1843\" download_time_ms=\"1000\" previousversion=\"0.0\" "
3305 "nextversion=\"1.0\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213306 events[0].c_str());
3307 EXPECT_STREQ(
Sorin Jianu7b00a132017-06-19 21:56:543308 "<event eventtype=\"42\" eventresult=\"1\" "
3309 "errorcode=\"1877345072\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213310 events[1].c_str());
Minh X. Nguyen01d3586d2018-01-03 21:53:393311 EXPECT_STREQ(
3312 "<event eventtype=\"3\" eventresult=\"1\" previousversion=\"0.0\" "
3313 "nextversion=\"1.0\"/>",
3314 events[2].c_str());
Sorin Jianu4ab7c292017-06-15 18:40:213315 }
3316 };
3317
3318 scoped_refptr<UpdateClient> update_client =
3319 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533320 config(), base::MakeRefCounted<MockPingManager>(config()),
3321 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:213322
Sorin Jianu7b00a132017-06-19 21:56:543323 // The action is a program which returns 1877345072 as a hardcoded value.
Sorin Jianu4ab7c292017-06-15 18:40:213324 update_client->Install(
Sorin Jianue5bfb5b2017-06-20 21:30:563325 std::string("gjpmebpgbhcamgdgjcmnjfhggjpgcimm"),
Sorin Jianu7c22795b2018-04-26 22:16:523326 base::BindOnce([](const std::vector<std::string>& ids) {
3327 auto crx = std::make_unique<CrxComponent>();
3328 crx->name = "test_niea";
Sorin Jianucb4431a2018-04-30 20:59:243329 crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523330 crx->version = base::Version("0.0");
3331 crx->installer = base::MakeRefCounted<VersionedTestInstaller>();
3332 std::vector<std::unique_ptr<CrxComponent>> component;
3333 component.push_back(std::move(crx));
3334 return component;
Sorin Jianu4ab7c292017-06-15 18:40:213335 }),
Sorin Jianua8ef73d2017-11-02 16:55:173336 base::BindOnce(
3337 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:213338 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173339 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213340 },
3341 quit_closure()));
3342
3343 RunThreads();
3344}
3345
3346// Tests that a run action is invoked in an update scenario when there was
3347// no update.
3348TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:533349 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:213350 public:
3351 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423352 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:213353 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533354 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:213355 }
3356
Sorin Jianud69d4372018-02-07 19:44:223357 void CheckForUpdates(const std::string& session_id,
3358 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173359 const IdToComponentPtrMap& components,
3360 const std::string& additional_attributes,
3361 bool enabled_component_updates,
3362 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:213363 /*
Sorin Jianua8926bf2018-03-09 21:02:533364 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:213365
3366 <?xml version='1.0' encoding='UTF-8'?>
3367 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:563368 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:213369 <updatecheck status='noupdate'>
3370 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:563371 <action run=ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:213372 </actions>"
3373 </updatecheck>
3374 </app>
3375 </response>
3376 */
Sorin Jianud69d4372018-02-07 19:44:223377 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:213378 EXPECT_EQ(1u, ids_to_check.size());
Sorin Jianue5bfb5b2017-06-20 21:30:563379 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:213380 EXPECT_EQ(id, ids_to_check[0]);
3381 EXPECT_EQ(1u, components.count(id));
3382
3383 auto& component = components.at(id);
3384
3385 ProtocolParser::Result result;
3386 result.extension_id = id;
3387 result.status = "noupdate";
Sorin Jianue5bfb5b2017-06-20 21:30:563388 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:213389
3390 component->SetParseResult(result);
3391
3392 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:173393 FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:213394 }
3395 };
3396
Sorin Jianua8926bf2018-03-09 21:02:533397 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:213398 public:
3399 static std::unique_ptr<CrxDownloader> Create(
3400 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213401 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533402 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:213403 }
3404
Sorin Jianua8926bf2018-03-09 21:02:533405 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:213406
3407 private:
3408 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3409 };
3410
Sorin Jianua8926bf2018-03-09 21:02:533411 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:213412 public:
Sorin Jianua8926bf2018-03-09 21:02:533413 explicit MockPingManager(scoped_refptr<Configurator> config)
3414 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543415
3416 protected:
Sorin Jianua8926bf2018-03-09 21:02:533417 ~MockPingManager() override {
3418 const auto& events = MockPingManagerImpl::events();
Sorin Jianu4ab7c292017-06-15 18:40:213419 EXPECT_EQ(1u, events.size());
3420 EXPECT_STREQ(
Sorin Jianu7b00a132017-06-19 21:56:543421 "<event eventtype=\"42\" eventresult=\"1\" "
3422 "errorcode=\"1877345072\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213423 events[0].c_str());
3424 }
3425 };
3426
3427 // Unpack the CRX to mock an existing install to be updated. The payload to
3428 // run is going to be picked up from this directory.
3429 base::FilePath unpack_path;
3430 {
3431 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:173432 base::OnceClosure quit_closure = runloop.QuitClosure();
Sorin Jianu4ab7c292017-06-15 18:40:213433
Joshua Pawlicki6d764422018-02-21 15:23:103434 auto config = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu7c22795b2018-04-26 22:16:523435 auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
Sorin Jianue5bfb5b2017-06-20 21:30:563436 std::vector<uint8_t>(std::begin(gjpm_hash), std::end(gjpm_hash)),
Joshua Pawlicki6d764422018-02-21 15:23:103437 TestFilePath("runaction_test_win.crx3"), nullptr,
3438 config->CreateServiceManagerConnector());
Sorin Jianu4ab7c292017-06-15 18:40:213439
Sorin Jianua8ef73d2017-11-02 16:55:173440 component_unpacker->Unpack(base::BindOnce(
3441 [](base::FilePath* unpack_path, base::OnceClosure quit_closure,
Sorin Jianu4ab7c292017-06-15 18:40:213442 const ComponentUnpacker::Result& result) {
3443 EXPECT_EQ(UnpackerError::kNone, result.error);
3444 EXPECT_EQ(0, result.extended_error);
3445 *unpack_path = result.unpack_path;
Sorin Jianua8ef73d2017-11-02 16:55:173446 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213447 },
3448 &unpack_path, runloop.QuitClosure()));
3449
3450 runloop.Run();
3451 }
3452
3453 EXPECT_FALSE(unpack_path.empty());
3454 EXPECT_TRUE(base::DirectoryExists(unpack_path));
3455 int64_t file_size = 0;
Sorin Jianue5bfb5b2017-06-20 21:30:563456 EXPECT_TRUE(base::GetFileSize(unpack_path.AppendASCII("ChromeRecovery.crx3"),
3457 &file_size));
3458 EXPECT_EQ(44582, file_size);
Sorin Jianu4ab7c292017-06-15 18:40:213459
3460 base::ScopedTempDir unpack_path_owner;
3461 EXPECT_TRUE(unpack_path_owner.Set(unpack_path));
3462
3463 scoped_refptr<UpdateClient> update_client =
3464 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533465 config(), base::MakeRefCounted<MockPingManager>(config()),
3466 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:213467
Sorin Jianu7b00a132017-06-19 21:56:543468 // The action is a program which returns 1877345072 as a hardcoded value.
Sorin Jianue5bfb5b2017-06-20 21:30:563469 const std::vector<std::string> ids = {"gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
Sorin Jianu4ab7c292017-06-15 18:40:213470 update_client->Update(
3471 ids,
Sorin Jianua8ef73d2017-11-02 16:55:173472 base::BindOnce(
Sorin Jianu4ab7c292017-06-15 18:40:213473 [](const base::FilePath& unpack_path,
Sorin Jianu7c22795b2018-04-26 22:16:523474 const std::vector<std::string>& ids) {
3475 auto crx = std::make_unique<CrxComponent>();
3476 crx->name = "test_niea";
Sorin Jianucb4431a2018-04-30 20:59:243477 crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523478 crx->version = base::Version("1.0");
3479 crx->installer =
Sorin Jianu4ab7c292017-06-15 18:40:213480 base::MakeRefCounted<ReadOnlyTestInstaller>(unpack_path);
Sorin Jianu7c22795b2018-04-26 22:16:523481 std::vector<std::unique_ptr<CrxComponent>> component;
3482 component.push_back(std::move(crx));
3483 return component;
Sorin Jianu4ab7c292017-06-15 18:40:213484 },
3485 unpack_path),
Sorin Jianub41a592a2018-03-02 16:30:273486 false,
Sorin Jianua8ef73d2017-11-02 16:55:173487 base::BindOnce(
3488 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:213489 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173490 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213491 },
3492 quit_closure()));
3493
3494 RunThreads();
3495}
3496
Sorin Jianu7b00a132017-06-19 21:56:543497#endif // OS_WIN
3498
sorin9797aba2015-04-17 17:15:033499} // namespace update_client