blob: 4e9900571dd5ea48d2b4ecc8d75e7a89aaefa0da [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"
Sorin Jianu888ec292018-06-01 15:35:4214#include "base/optional.h"
sorin9797aba2015-04-17 17:15:0315#include "base/path_service.h"
16#include "base/run_loop.h"
Sorin Jianucb4431a2018-04-30 20:59:2417#include "base/stl_util.h"
fdoray03349c12017-05-17 18:06:5118#include "base/task_scheduler/post_task.h"
Sorin Jianuf40ab4b32017-10-06 22:53:4119#include "base/task_scheduler/task_traits.h"
Sorin Jianu4ab7c292017-06-15 18:40:2120#include "base/test/scoped_path_override.h"
fdoray03349c12017-05-17 18:06:5121#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0122#include "base/threading/thread_task_runner_handle.h"
sorin9797aba2015-04-17 17:15:0323#include "base/values.h"
24#include "base/version.h"
Sorin Jianu188907072018-01-22 18:42:2225#include "build/build_config.h"
wafflesd2d9a332016-04-09 01:59:5726#include "components/prefs/testing_pref_service.h"
Sorin Jianu4ab7c292017-06-15 18:40:2127#include "components/update_client/component_unpacker.h"
sorin9797aba2015-04-17 17:15:0328#include "components/update_client/crx_update_item.h"
wafflesd2d9a332016-04-09 01:59:5729#include "components/update_client/persisted_data.h"
sorin9797aba2015-04-17 17:15:0330#include "components/update_client/ping_manager.h"
sorin7cff6e52017-05-17 16:37:2331#include "components/update_client/protocol_parser.h"
sorinb120440b2015-04-27 16:34:1532#include "components/update_client/test_configurator.h"
33#include "components/update_client/test_installer.h"
sorin9797aba2015-04-17 17:15:0334#include "components/update_client/update_checker.h"
sorin7b8650522016-11-02 18:23:4135#include "components/update_client/update_client_errors.h"
sorin9797aba2015-04-17 17:15:0336#include "components/update_client/update_client_internal.h"
sorin9797aba2015-04-17 17:15:0337#include "testing/gmock/include/gmock/gmock.h"
38#include "testing/gtest/include/gtest/gtest.h"
39#include "url/gurl.h"
40
41namespace update_client {
42
43namespace {
44
45using base::FilePath;
46
47// Makes a copy of the file specified by |from_path| in a temporary directory
48// and returns the path of the copy. Returns true if successful. Cleans up if
49// there was an error creating the copy.
50bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
51 FilePath temp_dir;
52 bool result =
53 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir);
54 if (!result)
55 return false;
56
57 FilePath temp_file;
58 result = CreateTemporaryFileInDir(temp_dir, &temp_file);
59 if (!result)
60 return false;
61
62 result = CopyFile(from_path, temp_file);
63 if (!result) {
64 DeleteFile(temp_file, false);
65 return false;
66 }
67
68 *to_path = temp_file;
69 return true;
70}
71
72using Events = UpdateClient::Observer::Events;
73
74class MockObserver : public UpdateClient::Observer {
75 public:
76 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
77};
78
sorin30474f02017-04-27 00:45:4879} // namespace
sorin7c717622015-05-26 19:59:0980
sorin30474f02017-04-27 00:45:4881using ::testing::_;
82using ::testing::AtLeast;
83using ::testing::AnyNumber;
84using ::testing::DoAll;
85using ::testing::InSequence;
86using ::testing::Invoke;
87using ::testing::Mock;
88using ::testing::Return;
sorin7c717622015-05-26 19:59:0989
sorin30474f02017-04-27 00:45:4890using std::string;
sorin7c717622015-05-26 19:59:0991
Sorin Jianua8926bf2018-03-09 21:02:5392class MockPingManagerImpl : public PingManager {
sorin9797aba2015-04-17 17:15:0393 public:
sorin30474f02017-04-27 00:45:4894 struct PingData {
95 std::string id;
96 base::Version previous_version;
97 base::Version next_version;
Minh X. Nguyena4640cb2018-05-23 21:29:1098 ErrorCategory error_category = ErrorCategory::kNone;
sorin30474f02017-04-27 00:45:4899 int error_code = 0;
100 int extra_code1 = 0;
Minh X. Nguyena4640cb2018-05-23 21:29:10101 ErrorCategory diff_error_category = ErrorCategory::kNone;
sorin30474f02017-04-27 00:45:48102 int diff_error_code = 0;
103 bool diff_update_failed = false;
104 };
105
Sorin Jianua8926bf2018-03-09 21:02:53106 explicit MockPingManagerImpl(scoped_refptr<Configurator> config);
sorin9797aba2015-04-17 17:15:03107
Sorin Jianu560d5022018-02-12 23:11:54108 void SendPing(const Component& component, Callback callback) override;
sorin9797aba2015-04-17 17:15:03109
sorin30474f02017-04-27 00:45:48110 const std::vector<PingData>& ping_data() const;
sorin9797aba2015-04-17 17:15:03111
Sorin Jianu4ab7c292017-06-15 18:40:21112 const std::vector<std::string>& events() const;
113
Sorin Jianu560d5022018-02-12 23:11:54114 protected:
Sorin Jianua8926bf2018-03-09 21:02:53115 ~MockPingManagerImpl() override;
Sorin Jianu560d5022018-02-12 23:11:54116
sorin9797aba2015-04-17 17:15:03117 private:
sorin30474f02017-04-27 00:45:48118 std::vector<PingData> ping_data_;
Sorin Jianu4ab7c292017-06-15 18:40:21119 std::vector<std::string> events_;
Sorin Jianua8926bf2018-03-09 21:02:53120 DISALLOW_COPY_AND_ASSIGN(MockPingManagerImpl);
sorin9797aba2015-04-17 17:15:03121};
122
Sorin Jianua8926bf2018-03-09 21:02:53123MockPingManagerImpl::MockPingManagerImpl(scoped_refptr<Configurator> config)
sorin958b5d32016-01-09 02:00:20124 : PingManager(config) {}
sorin9797aba2015-04-17 17:15:03125
Sorin Jianua8926bf2018-03-09 21:02:53126MockPingManagerImpl::~MockPingManagerImpl() {}
sorin9797aba2015-04-17 17:15:03127
Sorin Jianua8926bf2018-03-09 21:02:53128void MockPingManagerImpl::SendPing(const Component& component,
Sorin Jianu560d5022018-02-12 23:11:54129 Callback callback) {
sorin30474f02017-04-27 00:45:48130 PingData ping_data;
131 ping_data.id = component.id_;
132 ping_data.previous_version = component.previous_version_;
133 ping_data.next_version = component.next_version_;
134 ping_data.error_category = component.error_category_;
135 ping_data.error_code = component.error_code_;
136 ping_data.extra_code1 = component.extra_code1_;
137 ping_data.diff_error_category = component.diff_error_category_;
138 ping_data.diff_error_code = component.diff_error_code_;
139 ping_data.diff_update_failed = component.diff_update_failed();
140 ping_data_.push_back(ping_data);
Sorin Jianu4ab7c292017-06-15 18:40:21141
142 const auto& events = component.events();
143 events_.insert(events_.end(), events.begin(), events.end());
144
Sorin Jianu560d5022018-02-12 23:11:54145 std::move(callback).Run(0, "");
sorin9797aba2015-04-17 17:15:03146}
147
Sorin Jianua8926bf2018-03-09 21:02:53148const std::vector<MockPingManagerImpl::PingData>&
149MockPingManagerImpl::ping_data() const {
sorin30474f02017-04-27 00:45:48150 return ping_data_;
sorin9797aba2015-04-17 17:15:03151}
152
Sorin Jianua8926bf2018-03-09 21:02:53153const std::vector<std::string>& MockPingManagerImpl::events() const {
Sorin Jianu4ab7c292017-06-15 18:40:21154 return events_;
155}
156
sorin9797aba2015-04-17 17:15:03157class UpdateClientTest : public testing::Test {
158 public:
159 UpdateClientTest();
160 ~UpdateClientTest() override;
161
sorin9797aba2015-04-17 17:15:03162 protected:
163 void RunThreads();
164
165 // Returns the full path to a test file.
166 static base::FilePath TestFilePath(const char* file);
167
sorine84ff702016-08-04 01:22:02168 scoped_refptr<update_client::TestConfigurator> config() { return config_; }
wafflese7dff732016-04-15 23:51:49169 update_client::PersistedData* metadata() { return metadata_.get(); }
sorin9797aba2015-04-17 17:15:03170
Sorin Jianua8ef73d2017-11-02 16:55:17171 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
sorinf9f4834d2015-04-28 17:15:02172
173 private:
sorin30474f02017-04-27 00:45:48174 static constexpr int kNumWorkerThreads_ = 2;
sorinf9f4834d2015-04-28 17:15:02175
fdoray03349c12017-05-17 18:06:51176 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin9797aba2015-04-17 17:15:03177 base::RunLoop runloop_;
sorin9797aba2015-04-17 17:15:03178
Sorin Jianucc048f892017-07-26 02:05:54179 scoped_refptr<update_client::TestConfigurator> config_ =
180 base::MakeRefCounted<TestConfigurator>();
181 std::unique_ptr<TestingPrefServiceSimple> pref_ =
Jinho Bangda4e4282018-01-03 13:21:23182 std::make_unique<TestingPrefServiceSimple>();
wafflesd2d9a332016-04-09 01:59:57183 std::unique_ptr<update_client::PersistedData> metadata_;
sorinf9f4834d2015-04-28 17:15:02184
sorin9797aba2015-04-17 17:15:03185 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
186};
187
sorin30474f02017-04-27 00:45:48188constexpr int UpdateClientTest::kNumWorkerThreads_;
189
Sorin Jianucc048f892017-07-26 02:05:54190UpdateClientTest::UpdateClientTest() {
wafflesd2d9a332016-04-09 01:59:57191 PersistedData::RegisterPrefs(pref_->registry());
Jinho Bangda4e4282018-01-03 13:21:23192 metadata_ = std::make_unique<PersistedData>(pref_.get(), nullptr);
sorin9797aba2015-04-17 17:15:03193}
194
195UpdateClientTest::~UpdateClientTest() {
sorin9797aba2015-04-17 17:15:03196}
197
198void UpdateClientTest::RunThreads() {
199 runloop_.Run();
Sorin Jianuf40ab4b32017-10-06 22:53:41200 scoped_task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03201}
202
203base::FilePath UpdateClientTest::TestFilePath(const char* file) {
204 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:53205 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin9797aba2015-04-17 17:15:03206 return path.AppendASCII("components")
207 .AppendASCII("test")
208 .AppendASCII("data")
209 .AppendASCII("update_client")
210 .AppendASCII(file);
211}
212
213// Tests the scenario where one update check is done for one CRX. The CRX
214// has no update.
215TEST_F(UpdateClientTest, OneCrxNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53216 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03217 public:
Sorin Jianu7c22795b2018-04-26 22:16:52218 static std::vector<std::unique_ptr<CrxComponent>> Callback(
219 const std::vector<std::string>& ids) {
220 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
221 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:24222 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52223 crx->version = base::Version("0.9");
224 crx->installer = base::MakeRefCounted<TestInstaller>();
225 std::vector<std::unique_ptr<CrxComponent>> component;
226 component.push_back(std::move(crx));
227 return component;
sorin9797aba2015-04-17 17:15:03228 }
229 };
230
Sorin Jianua8926bf2018-03-09 21:02:53231 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03232 public:
Sorin Jianua8ef73d2017-11-02 16:55:17233 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41234 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17235 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03236 }
237 };
238
Sorin Jianua8926bf2018-03-09 21:02:53239 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03240 public:
dchengd0fc6aa92016-04-22 18:03:12241 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42242 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49243 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53244 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03245 }
246
Sorin Jianud69d4372018-02-07 19:44:22247 void CheckForUpdates(const std::string& session_id,
248 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17249 const IdToComponentPtrMap& components,
250 const std::string& additional_attributes,
251 bool enabled_component_updates,
252 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:22253 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:36254 EXPECT_TRUE(enabled_component_updates);
sorin30474f02017-04-27 00:45:48255 EXPECT_EQ(1u, ids_to_check.size());
256 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
257 EXPECT_EQ(id, ids_to_check.front());
258 EXPECT_EQ(1u, components.count(id));
259
260 auto& component = components.at(id);
261
Sorin Jianub41a592a2018-03-02 16:30:27262 EXPECT_TRUE(component->is_foreground());
sorin30474f02017-04-27 00:45:48263
sorin7cff6e52017-05-17 16:37:23264 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48265 result.extension_id = id;
266 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:42267
268 ProtocolParser::Results results;
269 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48270
sorin9797aba2015-04-17 17:15:03271 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46272 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
273 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03274 }
275 };
276
Sorin Jianua8926bf2018-03-09 21:02:53277 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03278 public:
dchengd0fc6aa92016-04-22 18:03:12279 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03280 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21281 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53282 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03283 }
284
Sorin Jianua8926bf2018-03-09 21:02:53285 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03286
sorin30474f02017-04-27 00:45:48287 private:
sorin9797aba2015-04-17 17:15:03288 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
289 };
290
Sorin Jianua8926bf2018-03-09 21:02:53291 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03292 public:
Sorin Jianua8926bf2018-03-09 21:02:53293 explicit MockPingManager(scoped_refptr<Configurator> config)
294 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54295
296 protected:
Sorin Jianua8926bf2018-03-09 21:02:53297 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin9797aba2015-04-17 17:15:03298 };
299
sorin30474f02017-04-27 00:45:48300 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43301 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53302 config(), base::MakeRefCounted<MockPingManager>(config()),
303 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:09304
sorin9797aba2015-04-17 17:15:03305 MockObserver observer;
306 InSequence seq;
307 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
308 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
309 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
310 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
311
312 update_client->AddObserver(&observer);
313
sorin30474f02017-04-27 00:45:48314 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:03315 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:53316 ids, base::BindOnce(&DataCallbackMock::Callback), true,
317 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03318
319 RunThreads();
320
321 update_client->RemoveObserver(&observer);
322}
323
324// Tests the scenario where two CRXs are checked for updates. On CRX has
325// an update, the other CRX does not.
326TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53327 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03328 public:
Sorin Jianu7c22795b2018-04-26 22:16:52329 static std::vector<std::unique_ptr<CrxComponent>> Callback(
330 const std::vector<std::string>& ids) {
331 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
332 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:24333 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52334 crx1->version = base::Version("0.9");
335 crx1->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03336
Sorin Jianu7c22795b2018-04-26 22:16:52337 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
338 crx2->name = "test_abag";
Sorin Jianucb4431a2018-04-30 20:59:24339 crx2->pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
Sorin Jianu7c22795b2018-04-26 22:16:52340 crx2->version = base::Version("2.2");
341 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03342
Sorin Jianu7c22795b2018-04-26 22:16:52343 std::vector<std::unique_ptr<CrxComponent>> component;
344 component.push_back(std::move(crx1));
345 component.push_back(std::move(crx2));
346 return component;
sorin9797aba2015-04-17 17:15:03347 }
348 };
349
Sorin Jianua8926bf2018-03-09 21:02:53350 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03351 public:
Sorin Jianua8ef73d2017-11-02 16:55:17352 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41353 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17354 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03355 }
356 };
357
Sorin Jianua8926bf2018-03-09 21:02:53358 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03359 public:
dchengd0fc6aa92016-04-22 18:03:12360 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42361 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49362 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53363 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03364 }
365
Sorin Jianud69d4372018-02-07 19:44:22366 void CheckForUpdates(const std::string& session_id,
367 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17368 const IdToComponentPtrMap& components,
369 const std::string& additional_attributes,
370 bool enabled_component_updates,
371 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03372 /*
Sorin Jianua8926bf2018-03-09 21:02:53373 Mock the following response:
sorin9797aba2015-04-17 17:15:03374
375 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28376 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03377 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
378 <updatecheck status='ok'>
379 <urls>
380 <url codebase='http://localhost/download/'/>
381 </urls>
382 <manifest version='1.0' prodversionmin='11.0.1.0'>
383 <packages>
sorin74e70672016-02-03 03:13:10384 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
385 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
386 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03387 </packages>
388 </manifest>
389 </updatecheck>
390 </app>
Sorin Jianu888ec292018-06-01 15:35:42391 <app appid='abagagagagagagagagagagagagagagag'>
392 <updatecheck status='noupdate'/>
393 </app>
sorin9797aba2015-04-17 17:15:03394 </response>
395 */
Sorin Jianud69d4372018-02-07 19:44:22396 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48397 EXPECT_TRUE(enabled_component_updates);
398 EXPECT_EQ(2u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03399
Sorin Jianu888ec292018-06-01 15:35:42400 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:48401 {
402 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
403 EXPECT_EQ(id, ids_to_check[0]);
404 EXPECT_EQ(1u, components.count(id));
405
sorin7cff6e52017-05-17 16:37:23406 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48407 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
408 package.hash_sha256 =
409 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
410
sorin7cff6e52017-05-17 16:37:23411 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48412 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
413 result.status = "ok";
414 result.crx_urls.push_back(GURL("http://localhost/download/"));
415 result.manifest.version = "1.0";
416 result.manifest.browser_min_version = "11.0.1.0";
417 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:42418 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48419
Sorin Jianu888ec292018-06-01 15:35:42420 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48421 }
422
423 {
424 const std::string id = "abagagagagagagagagagagagagagagag";
425 EXPECT_EQ(id, ids_to_check[1]);
426 EXPECT_EQ(1u, components.count(id));
427
sorin7cff6e52017-05-17 16:37:23428 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48429 result.extension_id = id;
430 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:42431 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48432
Sorin Jianu888ec292018-06-01 15:35:42433 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48434 }
sorin9797aba2015-04-17 17:15:03435
436 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46437 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
438 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03439 }
440 };
441
Sorin Jianua8926bf2018-03-09 21:02:53442 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03443 public:
dchengd0fc6aa92016-04-22 18:03:12444 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03445 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21446 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53447 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03448 }
449
Sorin Jianua8926bf2018-03-09 21:02:53450 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03451
sorin30474f02017-04-27 00:45:48452 private:
sorin9797aba2015-04-17 17:15:03453 void DoStartDownload(const GURL& url) override {
454 DownloadMetrics download_metrics;
455 download_metrics.url = url;
456 download_metrics.downloader = DownloadMetrics::kNone;
457 download_metrics.error = 0;
458 download_metrics.downloaded_bytes = 1843;
459 download_metrics.total_bytes = 1843;
460 download_metrics.download_time_ms = 1000;
461
462 FilePath path;
463 EXPECT_TRUE(MakeTestFile(
464 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
465
466 Result result;
467 result.error = 0;
468 result.response = path;
469 result.downloaded_bytes = 1843;
470 result.total_bytes = 1843;
471
472 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53473 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:58474 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:03475
476 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53477 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:58478 base::Unretained(this), true, result,
479 download_metrics));
sorin9797aba2015-04-17 17:15:03480 }
481 };
482
Sorin Jianua8926bf2018-03-09 21:02:53483 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03484 public:
Sorin Jianua8926bf2018-03-09 21:02:53485 explicit MockPingManager(scoped_refptr<Configurator> config)
486 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54487
488 protected:
Sorin Jianua8926bf2018-03-09 21:02:53489 ~MockPingManager() override {
490 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:48491 EXPECT_EQ(1u, ping_data.size());
492 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
493 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
494 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:10495 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:48496 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03497 }
498 };
499
sorin30474f02017-04-27 00:45:48500 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43501 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53502 config(), base::MakeRefCounted<MockPingManager>(config()),
503 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:03504
505 MockObserver observer;
506 {
507 InSequence seq;
508 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
509 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
510 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
511 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
512 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:48513 "jebgalgnebhfojomionfpkfelancnnkf"))
514 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:03515 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
516 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
517 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
518 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
519 }
520 {
521 InSequence seq;
522 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
523 "abagagagagagagagagagagagagagagag")).Times(1);
524 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
525 "abagagagagagagagagagagagagagagag")).Times(1);
526 }
527
528 update_client->AddObserver(&observer);
529
sorin30474f02017-04-27 00:45:48530 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
531 "abagagagagagagagagagagagagagagag"};
sorin9797aba2015-04-17 17:15:03532 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:53533 ids, base::BindOnce(&DataCallbackMock::Callback), false,
534 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03535
536 RunThreads();
537
538 update_client->RemoveObserver(&observer);
539}
540
Sorin Jianu888ec292018-06-01 15:35:42541// Tests the scenario where two CRXs are checked for updates. One CRX has
542// an update but the server ignores the second CRX and returns no response for
543// it. The second component gets an |UPDATE_RESPONSE_NOT_FOUND| error and
544// transitions to the error state.
545TEST_F(UpdateClientTest, TwoCrxUpdateFirstServerIgnoresSecond) {
546 class DataCallbackMock {
547 public:
548 static std::vector<std::unique_ptr<CrxComponent>> Callback(
549 const std::vector<std::string>& ids) {
550 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
551 crx1->name = "test_jebg";
552 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
553 crx1->version = base::Version("0.9");
554 crx1->installer = base::MakeRefCounted<TestInstaller>();
555
556 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
557 crx2->name = "test_abag";
558 crx2->pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
559 crx2->version = base::Version("2.2");
560 crx2->installer = base::MakeRefCounted<TestInstaller>();
561
562 std::vector<std::unique_ptr<CrxComponent>> component;
563 component.push_back(std::move(crx1));
564 component.push_back(std::move(crx2));
565 return component;
566 }
567 };
568
569 class CompletionCallbackMock {
570 public:
571 static void Callback(base::OnceClosure quit_closure, Error error) {
572 EXPECT_EQ(Error::NONE, error);
573 std::move(quit_closure).Run();
574 }
575 };
576
577 class MockUpdateChecker : public UpdateChecker {
578 public:
579 static std::unique_ptr<UpdateChecker> Create(
580 scoped_refptr<Configurator> config,
581 PersistedData* metadata) {
582 return std::make_unique<MockUpdateChecker>();
583 }
584
585 void CheckForUpdates(const std::string& session_id,
586 const std::vector<std::string>& ids_to_check,
587 const IdToComponentPtrMap& components,
588 const std::string& additional_attributes,
589 bool enabled_component_updates,
590 UpdateCheckCallback update_check_callback) override {
591 /*
592 Mock the following response:
593
594 <?xml version='1.0' encoding='UTF-8'?>
595 <response protocol='3.1'>
596 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
597 <updatecheck status='ok'>
598 <urls>
599 <url codebase='http://localhost/download/'/>
600 </urls>
601 <manifest version='1.0' prodversionmin='11.0.1.0'>
602 <packages>
603 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
604 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
605 7c9b12cb7cc067667bde87'/>
606 </packages>
607 </manifest>
608 </updatecheck>
609 </app>
610 </response>
611 */
612 EXPECT_FALSE(session_id.empty());
613 EXPECT_TRUE(enabled_component_updates);
614 EXPECT_EQ(2u, ids_to_check.size());
615
616 ProtocolParser::Results results;
617 {
618 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
619 EXPECT_EQ(id, ids_to_check[0]);
620 EXPECT_EQ(1u, components.count(id));
621
622 ProtocolParser::Result::Manifest::Package package;
623 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
624 package.hash_sha256 =
625 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
626
627 ProtocolParser::Result result;
628 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
629 result.status = "ok";
630 result.crx_urls.push_back(GURL("http://localhost/download/"));
631 result.manifest.version = "1.0";
632 result.manifest.browser_min_version = "11.0.1.0";
633 result.manifest.packages.push_back(package);
634 results.list.push_back(result);
635
636 EXPECT_FALSE(components.at(id)->is_foreground());
637 }
638
639 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46640 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
641 ErrorCategory::kNone, 0, 0));
Sorin Jianu888ec292018-06-01 15:35:42642 }
643 };
644
645 class MockCrxDownloader : public CrxDownloader {
646 public:
647 static std::unique_ptr<CrxDownloader> Create(
648 bool is_background_download,
649 scoped_refptr<net::URLRequestContextGetter> context_getter) {
650 return std::make_unique<MockCrxDownloader>();
651 }
652
653 MockCrxDownloader() : CrxDownloader(nullptr) {}
654
655 private:
656 void DoStartDownload(const GURL& url) override {
657 DownloadMetrics download_metrics;
658 download_metrics.url = url;
659 download_metrics.downloader = DownloadMetrics::kNone;
660 download_metrics.error = 0;
661 download_metrics.downloaded_bytes = 1843;
662 download_metrics.total_bytes = 1843;
663 download_metrics.download_time_ms = 1000;
664
665 FilePath path;
666 EXPECT_TRUE(MakeTestFile(
667 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
668
669 Result result;
670 result.error = 0;
671 result.response = path;
672 result.downloaded_bytes = 1843;
673 result.total_bytes = 1843;
674
675 base::ThreadTaskRunnerHandle::Get()->PostTask(
676 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
677 base::Unretained(this), result));
678
679 base::ThreadTaskRunnerHandle::Get()->PostTask(
680 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
681 base::Unretained(this), true, result,
682 download_metrics));
683 }
684 };
685
686 class MockPingManager : public MockPingManagerImpl {
687 public:
688 explicit MockPingManager(scoped_refptr<Configurator> config)
689 : MockPingManagerImpl(config) {}
690
691 protected:
692 ~MockPingManager() override {
693 const auto ping_data = MockPingManagerImpl::ping_data();
694 EXPECT_EQ(1u, ping_data.size());
695 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
696 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
697 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
698 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
699 EXPECT_EQ(0, ping_data[0].error_code);
700 }
701 };
702
703 scoped_refptr<UpdateClient> update_client =
704 base::MakeRefCounted<UpdateClientImpl>(
705 config(), base::MakeRefCounted<MockPingManager>(config()),
706 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
707
708 MockObserver observer;
709 {
710 InSequence seq;
711 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
712 "jebgalgnebhfojomionfpkfelancnnkf"))
713 .Times(1);
714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
715 "jebgalgnebhfojomionfpkfelancnnkf"))
716 .Times(1);
717 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
718 "jebgalgnebhfojomionfpkfelancnnkf"))
719 .Times(AtLeast(1));
720 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
721 "jebgalgnebhfojomionfpkfelancnnkf"))
722 .Times(1);
723 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
724 "jebgalgnebhfojomionfpkfelancnnkf"))
725 .Times(1);
726 }
727 {
728 InSequence seq;
729 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
730 "abagagagagagagagagagagagagagagag"))
731 .Times(1);
732 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
733 "abagagagagagagagagagagagagagagag"))
734 .Times(1)
735 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
736 CrxUpdateItem item;
737 update_client->GetCrxUpdateState(id, &item);
738 EXPECT_EQ(ComponentState::kUpdateError, item.state);
739 EXPECT_EQ(5, static_cast<int>(item.error_category));
740 EXPECT_EQ(-10004, item.error_code);
741 EXPECT_EQ(0, item.extra_code1);
742 }));
743 }
744
745 update_client->AddObserver(&observer);
746
747 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
748 "abagagagagagagagagagagagagagagag"};
749 update_client->Update(
750 ids, base::BindOnce(&DataCallbackMock::Callback), false,
751 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
752
753 RunThreads();
754
755 update_client->RemoveObserver(&observer);
756}
757
Sorin Jianucb4431a2018-04-30 20:59:24758// Tests the update check for two CRXs scenario when the second CRX does not
759// provide a CrxComponent instance. In this case, the update is handled as
760// if only one component were provided as an argument to the |Update| call
761// with the exception that the second component still fires an event such as
762// |COMPONENT_UPDATE_ERROR|.
763TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentData) {
Sorin Jianua8926bf2018-03-09 21:02:53764 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03765 public:
Sorin Jianu7c22795b2018-04-26 22:16:52766 static std::vector<std::unique_ptr<CrxComponent>> Callback(
767 const std::vector<std::string>& ids) {
Sorin Jianucb4431a2018-04-30 20:59:24768 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
769 crx->name = "test_jebg";
770 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
771 crx->version = base::Version("0.9");
772 crx->installer = base::MakeRefCounted<TestInstaller>();
sorin9797aba2015-04-17 17:15:03773
Sorin Jianu7c22795b2018-04-26 22:16:52774 std::vector<std::unique_ptr<CrxComponent>> component;
Sorin Jianucb4431a2018-04-30 20:59:24775 component.push_back(std::move(crx));
776 component.push_back(std::move(nullptr));
Sorin Jianu7c22795b2018-04-26 22:16:52777 return component;
sorin9797aba2015-04-17 17:15:03778 }
779 };
780
Sorin Jianua8926bf2018-03-09 21:02:53781 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03782 public:
Sorin Jianua8ef73d2017-11-02 16:55:17783 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41784 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17785 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03786 }
787 };
788
Sorin Jianua8926bf2018-03-09 21:02:53789 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03790 public:
dchengd0fc6aa92016-04-22 18:03:12791 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42792 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49793 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53794 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03795 }
796
Sorin Jianud69d4372018-02-07 19:44:22797 void CheckForUpdates(const std::string& session_id,
798 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:17799 const IdToComponentPtrMap& components,
800 const std::string& additional_attributes,
801 bool enabled_component_updates,
802 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03803 /*
Sorin Jianua8926bf2018-03-09 21:02:53804 Mock the following response:
sorin9797aba2015-04-17 17:15:03805
806 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28807 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03808 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
809 <updatecheck status='ok'>
810 <urls>
811 <url codebase='http://localhost/download/'/>
812 </urls>
813 <manifest version='1.0' prodversionmin='11.0.1.0'>
814 <packages>
sorin74e70672016-02-03 03:13:10815 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
816 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
817 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:03818 </packages>
819 </manifest>
820 </updatecheck>
821 </app>
sorin9797aba2015-04-17 17:15:03822 </response>
823 */
Sorin Jianud69d4372018-02-07 19:44:22824 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48825 EXPECT_TRUE(enabled_component_updates);
Sorin Jianucb4431a2018-04-30 20:59:24826 EXPECT_EQ(1u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03827
Sorin Jianu888ec292018-06-01 15:35:42828 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:48829 {
830 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
831 EXPECT_EQ(id, ids_to_check[0]);
832 EXPECT_EQ(1u, components.count(id));
sorin9797aba2015-04-17 17:15:03833
sorin7cff6e52017-05-17 16:37:23834 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48835 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
836 package.hash_sha256 =
837 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin9797aba2015-04-17 17:15:03838
sorin7cff6e52017-05-17 16:37:23839 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48840 result.extension_id = id;
841 result.status = "ok";
842 result.crx_urls.push_back(GURL("http://localhost/download/"));
843 result.manifest.version = "1.0";
844 result.manifest.browser_min_version = "11.0.1.0";
845 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:42846 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:03847
Sorin Jianu888ec292018-06-01 15:35:42848 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48849 }
850
sorin9797aba2015-04-17 17:15:03851 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46852 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
853 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03854 }
855 };
856
Sorin Jianua8926bf2018-03-09 21:02:53857 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03858 public:
dchengd0fc6aa92016-04-22 18:03:12859 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03860 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:21861 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:53862 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03863 }
864
Sorin Jianua8926bf2018-03-09 21:02:53865 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03866
sorin30474f02017-04-27 00:45:48867 private:
sorin9797aba2015-04-17 17:15:03868 void DoStartDownload(const GURL& url) override {
869 DownloadMetrics download_metrics;
870 FilePath path;
871 Result result;
872 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
873 download_metrics.url = url;
874 download_metrics.downloader = DownloadMetrics::kNone;
875 download_metrics.error = 0;
876 download_metrics.downloaded_bytes = 1843;
877 download_metrics.total_bytes = 1843;
878 download_metrics.download_time_ms = 1000;
879
880 EXPECT_TRUE(MakeTestFile(
881 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
882
883 result.error = 0;
884 result.response = path;
885 result.downloaded_bytes = 1843;
886 result.total_bytes = 1843;
sorin9797aba2015-04-17 17:15:03887 } else {
888 NOTREACHED();
889 }
890
891 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53892 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:58893 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:03894
895 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53896 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianua8ef73d2017-11-02 16:55:17897 base::Unretained(this), true, result,
898 download_metrics));
sorin9797aba2015-04-17 17:15:03899 }
900 };
901
Sorin Jianua8926bf2018-03-09 21:02:53902 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03903 public:
Sorin Jianua8926bf2018-03-09 21:02:53904 explicit MockPingManager(scoped_refptr<Configurator> config)
905 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54906
907 protected:
Sorin Jianua8926bf2018-03-09 21:02:53908 ~MockPingManager() override {
909 const auto ping_data = MockPingManagerImpl::ping_data();
Sorin Jianucb4431a2018-04-30 20:59:24910 EXPECT_EQ(1u, ping_data.size());
sorin30474f02017-04-27 00:45:48911 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
912 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
913 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:10914 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:48915 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03916 }
917 };
918
sorin30474f02017-04-27 00:45:48919 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43920 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53921 config(), base::MakeRefCounted<MockPingManager>(config()),
922 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:03923
924 MockObserver observer;
925 {
926 InSequence seq;
927 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
928 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
929 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
930 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
931 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:48932 "jebgalgnebhfojomionfpkfelancnnkf"))
933 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:03934 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
935 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
936 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
937 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
938 }
939 {
940 InSequence seq;
Sorin Jianucb4431a2018-04-30 20:59:24941 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorin30474f02017-04-27 00:45:48942 "ihfokbkgjpifnbbojhneepfflplebdkc"))
Sorin Jianucb4431a2018-04-30 20:59:24943 .Times(1);
944 }
945
946 update_client->AddObserver(&observer);
947
948 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
949 "ihfokbkgjpifnbbojhneepfflplebdkc"};
950 update_client->Update(
951 ids, base::BindOnce(&DataCallbackMock::Callback), false,
952 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
953
954 RunThreads();
955
956 update_client->RemoveObserver(&observer);
957}
958
959// Tests the update check for two CRXs scenario when no CrxComponent data is
960// provided for either component. In this case, no update check occurs, and
961// |COMPONENT_UPDATE_ERROR| event fires for both components.
962TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentDataAtAll) {
963 class DataCallbackMock {
964 public:
965 static std::vector<std::unique_ptr<CrxComponent>> Callback(
966 const std::vector<std::string>& ids) {
967 std::vector<std::unique_ptr<CrxComponent>> component;
968 component.push_back(std::move(nullptr));
969 component.push_back(std::move(nullptr));
970 return component;
971 }
972 };
973
974 class CompletionCallbackMock {
975 public:
976 static void Callback(base::OnceClosure quit_closure, Error error) {
977 EXPECT_EQ(Error::NONE, error);
978 std::move(quit_closure).Run();
979 }
980 };
981
982 class MockUpdateChecker : public UpdateChecker {
983 public:
984 static std::unique_ptr<UpdateChecker> Create(
985 scoped_refptr<Configurator> config,
986 PersistedData* metadata) {
987 return std::make_unique<MockUpdateChecker>();
988 }
989
990 void CheckForUpdates(const std::string& session_id,
991 const std::vector<std::string>& ids_to_check,
992 const IdToComponentPtrMap& components,
993 const std::string& additional_attributes,
994 bool enabled_component_updates,
995 UpdateCheckCallback update_check_callback) override {
996 NOTREACHED();
997 }
998 };
999
1000 class MockCrxDownloader : public CrxDownloader {
1001 public:
1002 static std::unique_ptr<CrxDownloader> Create(
1003 bool is_background_download,
1004 scoped_refptr<net::URLRequestContextGetter> context_getter) {
1005 return std::make_unique<MockCrxDownloader>();
1006 }
1007
1008 MockCrxDownloader() : CrxDownloader(nullptr) {}
1009
1010 private:
1011 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
1012 };
1013
1014 class MockPingManager : public MockPingManagerImpl {
1015 public:
1016 explicit MockPingManager(scoped_refptr<Configurator> config)
1017 : MockPingManagerImpl(config) {}
1018
1019 protected:
1020 ~MockPingManager() override {
1021 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
1022 }
1023 };
1024
1025 scoped_refptr<UpdateClient> update_client =
1026 base::MakeRefCounted<UpdateClientImpl>(
1027 config(), base::MakeRefCounted<MockPingManager>(config()),
1028 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
1029
1030 MockObserver observer;
1031 {
1032 InSequence seq;
1033 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1034 "jebgalgnebhfojomionfpkfelancnnkf"))
1035 .Times(1);
1036 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1037 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1038 .Times(1);
sorin9797aba2015-04-17 17:15:031039 }
1040
1041 update_client->AddObserver(&observer);
1042
sorin30474f02017-04-27 00:45:481043 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1044 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031045 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:531046 ids, base::BindOnce(&DataCallbackMock::Callback), false,
1047 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031048
1049 RunThreads();
1050
1051 update_client->RemoveObserver(&observer);
1052}
1053
sorin6bb8de42015-06-03 00:23:271054// Tests the scenario where there is a download timeout for the first
1055// CRX. The update for the first CRX fails. The update client waits before
1056// attempting the update for the second CRX. This update succeeds.
1057TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
Sorin Jianua8926bf2018-03-09 21:02:531058 class DataCallbackMock {
sorin6bb8de42015-06-03 00:23:271059 public:
Sorin Jianu7c22795b2018-04-26 22:16:521060 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1061 const std::vector<std::string>& ids) {
1062 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
1063 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:241064 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521065 crx1->version = base::Version("0.9");
1066 crx1->installer = base::MakeRefCounted<TestInstaller>();
sorin6bb8de42015-06-03 00:23:271067
Sorin Jianu7c22795b2018-04-26 22:16:521068 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
1069 crx2->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:241070 crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521071 crx2->version = base::Version("0.8");
1072 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorin6bb8de42015-06-03 00:23:271073
Sorin Jianu7c22795b2018-04-26 22:16:521074 std::vector<std::unique_ptr<CrxComponent>> component;
1075 component.push_back(std::move(crx1));
1076 component.push_back(std::move(crx2));
1077 return component;
sorin6bb8de42015-06-03 00:23:271078 }
1079 };
1080
Sorin Jianua8926bf2018-03-09 21:02:531081 class CompletionCallbackMock {
sorin6bb8de42015-06-03 00:23:271082 public:
Sorin Jianua8ef73d2017-11-02 16:55:171083 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411084 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171085 std::move(quit_closure).Run();
sorin6bb8de42015-06-03 00:23:271086 }
1087 };
1088
Sorin Jianua8926bf2018-03-09 21:02:531089 class MockUpdateChecker : public UpdateChecker {
sorin6bb8de42015-06-03 00:23:271090 public:
dchengd0fc6aa92016-04-22 18:03:121091 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421092 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491093 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531094 return std::make_unique<MockUpdateChecker>();
sorin6bb8de42015-06-03 00:23:271095 }
1096
Sorin Jianud69d4372018-02-07 19:44:221097 void CheckForUpdates(const std::string& session_id,
1098 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171099 const IdToComponentPtrMap& components,
1100 const std::string& additional_attributes,
1101 bool enabled_component_updates,
1102 UpdateCheckCallback update_check_callback) override {
sorin6bb8de42015-06-03 00:23:271103 /*
Sorin Jianua8926bf2018-03-09 21:02:531104 Mock the following response:
sorin6bb8de42015-06-03 00:23:271105
1106 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281107 <response protocol='3.1'>
sorin6bb8de42015-06-03 00:23:271108 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1109 <updatecheck status='ok'>
1110 <urls>
1111 <url codebase='http://localhost/download/'/>
1112 </urls>
1113 <manifest version='1.0' prodversionmin='11.0.1.0'>
1114 <packages>
sorin74e70672016-02-03 03:13:101115 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1116 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1117 7c9b12cb7cc067667bde87'/>
sorin6bb8de42015-06-03 00:23:271118 </packages>
1119 </manifest>
1120 </updatecheck>
1121 </app>
1122 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1123 <updatecheck status='ok'>
1124 <urls>
1125 <url codebase='http://localhost/download/'/>
1126 </urls>
1127 <manifest version='1.0' prodversionmin='11.0.1.0'>
1128 <packages>
sorin74e70672016-02-03 03:13:101129 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1130 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
1131 309f156ea6d27229c0b3f9'/>
sorin6bb8de42015-06-03 00:23:271132 </packages>
1133 </manifest>
1134 </updatecheck>
1135 </app>
1136 </response>
1137 */
sorin6bb8de42015-06-03 00:23:271138
Sorin Jianud69d4372018-02-07 19:44:221139 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:481140 EXPECT_TRUE(enabled_component_updates);
1141 EXPECT_EQ(2u, ids_to_check.size());
sorin6bb8de42015-06-03 00:23:271142
Sorin Jianu888ec292018-06-01 15:35:421143 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:481144 {
1145 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
1146 EXPECT_EQ(id, ids_to_check[0]);
1147 EXPECT_EQ(1u, components.count(id));
sorin6bb8de42015-06-03 00:23:271148
sorin7cff6e52017-05-17 16:37:231149 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:481150 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
1151 package.hash_sha256 =
1152 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin6bb8de42015-06-03 00:23:271153
sorin7cff6e52017-05-17 16:37:231154 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481155 result.extension_id = id;
1156 result.status = "ok";
1157 result.crx_urls.push_back(GURL("http://localhost/download/"));
1158 result.manifest.version = "1.0";
1159 result.manifest.browser_min_version = "11.0.1.0";
1160 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421161 results.list.push_back(result);
sorin30474f02017-04-27 00:45:481162 }
1163
1164 {
1165 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1166 EXPECT_EQ(id, ids_to_check[1]);
1167 EXPECT_EQ(1u, components.count(id));
1168
sorin7cff6e52017-05-17 16:37:231169 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:481170 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
1171 package.hash_sha256 =
1172 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
1173
sorin7cff6e52017-05-17 16:37:231174 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481175 result.extension_id = id;
1176 result.status = "ok";
1177 result.crx_urls.push_back(GURL("http://localhost/download/"));
1178 result.manifest.version = "1.0";
1179 result.manifest.browser_min_version = "11.0.1.0";
1180 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421181 results.list.push_back(result);
sorin30474f02017-04-27 00:45:481182 }
sorin6bb8de42015-06-03 00:23:271183
1184 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461185 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1186 ErrorCategory::kNone, 0, 0));
sorin6bb8de42015-06-03 00:23:271187 }
1188 };
1189
Sorin Jianua8926bf2018-03-09 21:02:531190 class MockCrxDownloader : public CrxDownloader {
sorin6bb8de42015-06-03 00:23:271191 public:
dchengd0fc6aa92016-04-22 18:03:121192 static std::unique_ptr<CrxDownloader> Create(
sorin6bb8de42015-06-03 00:23:271193 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211194 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531195 return std::make_unique<MockCrxDownloader>();
sorin6bb8de42015-06-03 00:23:271196 }
1197
Sorin Jianua8926bf2018-03-09 21:02:531198 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin6bb8de42015-06-03 00:23:271199
sorin30474f02017-04-27 00:45:481200 private:
sorin6bb8de42015-06-03 00:23:271201 void DoStartDownload(const GURL& url) override {
1202 DownloadMetrics download_metrics;
1203 FilePath path;
1204 Result result;
1205 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
1206 download_metrics.url = url;
1207 download_metrics.downloader = DownloadMetrics::kNone;
1208 download_metrics.error = -118;
1209 download_metrics.downloaded_bytes = 0;
1210 download_metrics.total_bytes = 0;
1211 download_metrics.download_time_ms = 1000;
1212
Sorin Jianu52de5fa2017-10-09 23:19:331213 // The result must not include a file path in the case of errors.
sorin6bb8de42015-06-03 00:23:271214 result.error = -118;
sorin6bb8de42015-06-03 00:23:271215 result.downloaded_bytes = 0;
1216 result.total_bytes = 0;
1217 } else if (url.path() ==
1218 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1219 download_metrics.url = url;
1220 download_metrics.downloader = DownloadMetrics::kNone;
1221 download_metrics.error = 0;
1222 download_metrics.downloaded_bytes = 53638;
1223 download_metrics.total_bytes = 53638;
1224 download_metrics.download_time_ms = 2000;
1225
1226 EXPECT_TRUE(MakeTestFile(
1227 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1228
1229 result.error = 0;
1230 result.response = path;
1231 result.downloaded_bytes = 53638;
1232 result.total_bytes = 53638;
1233 } else {
1234 NOTREACHED();
1235 }
1236
1237 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531238 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:581239 base::Unretained(this), result));
sorin6bb8de42015-06-03 00:23:271240
1241 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531242 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581243 base::Unretained(this), true, result,
1244 download_metrics));
sorin6bb8de42015-06-03 00:23:271245 }
1246 };
1247
Sorin Jianua8926bf2018-03-09 21:02:531248 class MockPingManager : public MockPingManagerImpl {
sorin6bb8de42015-06-03 00:23:271249 public:
Sorin Jianua8926bf2018-03-09 21:02:531250 explicit MockPingManager(scoped_refptr<Configurator> config)
1251 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541252
1253 protected:
Sorin Jianua8926bf2018-03-09 21:02:531254 ~MockPingManager() override {
1255 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481256 EXPECT_EQ(2u, ping_data.size());
1257 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1258 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1259 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101260 EXPECT_EQ(1, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:481261 EXPECT_EQ(-118, ping_data[0].error_code);
1262 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1263 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
1264 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101265 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:481266 EXPECT_EQ(0, ping_data[1].error_code);
sorin6bb8de42015-06-03 00:23:271267 }
1268 };
1269
sorin30474f02017-04-27 00:45:481270 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431271 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531272 config(), base::MakeRefCounted<MockPingManager>(config()),
1273 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin6bb8de42015-06-03 00:23:271274
1275 MockObserver observer;
1276 {
1277 InSequence seq;
1278 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1279 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1280 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1281 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1282 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481283 "jebgalgnebhfojomionfpkfelancnnkf"))
1284 .Times(AtLeast(1));
Sorin Jianucbb10e12018-01-23 18:01:441285 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1286 "jebgalgnebhfojomionfpkfelancnnkf"))
Sorin Jianuafcb70dd2018-05-16 20:14:151287 .Times(1)
1288 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
1289 CrxUpdateItem item;
1290 update_client->GetCrxUpdateState(id, &item);
1291 EXPECT_EQ(ComponentState::kUpdateError, item.state);
Minh X. Nguyena4640cb2018-05-23 21:29:101292 EXPECT_EQ(1, static_cast<int>(item.error_category));
Sorin Jianuafcb70dd2018-05-16 20:14:151293 EXPECT_EQ(-118, item.error_code);
1294 EXPECT_EQ(0, item.extra_code1);
1295 }));
sorin6bb8de42015-06-03 00:23:271296 }
1297 {
1298 InSequence seq;
1299 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1300 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1301 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1302 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1303 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
1304 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1305 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481306 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1307 .Times(AtLeast(1));
sorin6bb8de42015-06-03 00:23:271308 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1309 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1310 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1311 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1312 }
1313
1314 update_client->AddObserver(&observer);
1315
sorin30474f02017-04-27 00:45:481316 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1317 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin6bb8de42015-06-03 00:23:271318
1319 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:531320 ids, base::BindOnce(&DataCallbackMock::Callback), false,
1321 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin6bb8de42015-06-03 00:23:271322
1323 RunThreads();
1324
1325 update_client->RemoveObserver(&observer);
sorin6bb8de42015-06-03 00:23:271326}
1327
sorin9797aba2015-04-17 17:15:031328// Tests the differential update scenario for one CRX.
1329TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:531330 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031331 public:
Sorin Jianu7c22795b2018-04-26 22:16:521332 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1333 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:031334 static int num_calls = 0;
1335
1336 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:481337 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431338 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:031339
1340 ++num_calls;
1341
Sorin Jianu7c22795b2018-04-26 22:16:521342 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1343 crx->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:241344 crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521345 crx->installer = installer;
sorin9797aba2015-04-17 17:15:031346 if (num_calls == 1) {
Sorin Jianu7c22795b2018-04-26 22:16:521347 crx->version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031348 } else if (num_calls == 2) {
Sorin Jianu7c22795b2018-04-26 22:16:521349 crx->version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031350 } else {
1351 NOTREACHED();
1352 }
1353
Sorin Jianu7c22795b2018-04-26 22:16:521354 std::vector<std::unique_ptr<CrxComponent>> component;
1355 component.push_back(std::move(crx));
1356 return component;
sorin9797aba2015-04-17 17:15:031357 }
1358 };
1359
Sorin Jianua8926bf2018-03-09 21:02:531360 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031361 public:
Sorin Jianua8ef73d2017-11-02 16:55:171362 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411363 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171364 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031365 }
1366 };
1367
Sorin Jianua8926bf2018-03-09 21:02:531368 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031369 public:
dchengd0fc6aa92016-04-22 18:03:121370 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421371 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491372 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531373 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031374 }
1375
Sorin Jianud69d4372018-02-07 19:44:221376 void CheckForUpdates(const std::string& session_id,
1377 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171378 const IdToComponentPtrMap& components,
1379 const std::string& additional_attributes,
1380 bool enabled_component_updates,
1381 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:221382 EXPECT_FALSE(session_id.empty());
1383
sorin9797aba2015-04-17 17:15:031384 static int num_call = 0;
1385 ++num_call;
1386
sorin7cff6e52017-05-17 16:37:231387 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:031388
1389 if (num_call == 1) {
1390 /*
Sorin Jianua8926bf2018-03-09 21:02:531391 Mock the following response:
sorin9797aba2015-04-17 17:15:031392 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281393 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031394 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1395 <updatecheck status='ok'>
1396 <urls>
1397 <url codebase='http://localhost/download/'/>
1398 </urls>
1399 <manifest version='1.0' prodversionmin='11.0.1.0'>
1400 <packages>
sorin74e70672016-02-03 03:13:101401 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1402 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1403 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031404 </packages>
1405 </manifest>
1406 </updatecheck>
1407 </app>
1408 </response>
1409 */
sorin30474f02017-04-27 00:45:481410 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1411 EXPECT_EQ(id, ids_to_check[0]);
1412 EXPECT_EQ(1u, components.count(id));
1413
sorin7cff6e52017-05-17 16:37:231414 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031415 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101416 package.hash_sha256 =
1417 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin30474f02017-04-27 00:45:481418
sorin7cff6e52017-05-17 16:37:231419 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481420 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171421 result.status = "ok";
sorin9797aba2015-04-17 17:15:031422 result.crx_urls.push_back(GURL("http://localhost/download/"));
1423 result.manifest.version = "1.0";
1424 result.manifest.browser_min_version = "11.0.1.0";
1425 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421426 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031427 } else if (num_call == 2) {
1428 /*
Sorin Jianua8926bf2018-03-09 21:02:531429 Mock the following response:
sorin9797aba2015-04-17 17:15:031430 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281431 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031432 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1433 <updatecheck status='ok'>
1434 <urls>
1435 <url codebase='http://localhost/download/'/>
1436 <url codebasediff='http://localhost/download/'/>
1437 </urls>
1438 <manifest version='2.0' prodversionmin='11.0.1.0'>
1439 <packages>
1440 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1441 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101442 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1443 0ecde26c262bad942b112990'
1444 fp='22'
1445 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261446 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031447 </packages>
1448 </manifest>
1449 </updatecheck>
1450 </app>
1451 </response>
1452 */
sorin30474f02017-04-27 00:45:481453 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1454 EXPECT_EQ(id, ids_to_check[0]);
1455 EXPECT_EQ(1u, components.count(id));
1456
sorin7cff6e52017-05-17 16:37:231457 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031458 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1459 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101460 package.hash_sha256 =
1461 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1462 package.hashdiff_sha256 =
1463 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031464 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:481465
sorin7cff6e52017-05-17 16:37:231466 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481467 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171468 result.status = "ok";
sorin9797aba2015-04-17 17:15:031469 result.crx_urls.push_back(GURL("http://localhost/download/"));
1470 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1471 result.manifest.version = "2.0";
1472 result.manifest.browser_min_version = "11.0.1.0";
1473 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421474 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031475 } else {
1476 NOTREACHED();
1477 }
1478
1479 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461480 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1481 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:031482 }
1483 };
1484
Sorin Jianua8926bf2018-03-09 21:02:531485 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031486 public:
dchengd0fc6aa92016-04-22 18:03:121487 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031488 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211489 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531490 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031491 }
1492
Sorin Jianua8926bf2018-03-09 21:02:531493 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031494
sorin30474f02017-04-27 00:45:481495 private:
sorin9797aba2015-04-17 17:15:031496 void DoStartDownload(const GURL& url) override {
1497 DownloadMetrics download_metrics;
1498 FilePath path;
1499 Result result;
1500 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1501 download_metrics.url = url;
1502 download_metrics.downloader = DownloadMetrics::kNone;
1503 download_metrics.error = 0;
1504 download_metrics.downloaded_bytes = 53638;
1505 download_metrics.total_bytes = 53638;
1506 download_metrics.download_time_ms = 2000;
1507
1508 EXPECT_TRUE(MakeTestFile(
1509 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1510
1511 result.error = 0;
1512 result.response = path;
1513 result.downloaded_bytes = 53638;
1514 result.total_bytes = 53638;
1515 } else if (url.path() ==
1516 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1517 download_metrics.url = url;
1518 download_metrics.downloader = DownloadMetrics::kNone;
1519 download_metrics.error = 0;
1520 download_metrics.downloaded_bytes = 2105;
1521 download_metrics.total_bytes = 2105;
1522 download_metrics.download_time_ms = 1000;
1523
1524 EXPECT_TRUE(MakeTestFile(
1525 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1526
1527 result.error = 0;
1528 result.response = path;
1529 result.downloaded_bytes = 2105;
1530 result.total_bytes = 2105;
1531 } else {
1532 NOTREACHED();
1533 }
1534
1535 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531536 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:581537 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:031538
1539 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531540 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581541 base::Unretained(this), true, result,
1542 download_metrics));
sorin9797aba2015-04-17 17:15:031543 }
1544 };
1545
Sorin Jianua8926bf2018-03-09 21:02:531546 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031547 public:
Sorin Jianua8926bf2018-03-09 21:02:531548 explicit MockPingManager(scoped_refptr<Configurator> config)
1549 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541550
1551 protected:
Sorin Jianua8926bf2018-03-09 21:02:531552 ~MockPingManager() override {
1553 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481554 EXPECT_EQ(2u, ping_data.size());
1555 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
1556 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
1557 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101558 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:481559 EXPECT_EQ(0, ping_data[0].error_code);
1560 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1561 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
1562 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
1563 EXPECT_FALSE(ping_data[1].diff_update_failed);
Minh X. Nguyena4640cb2018-05-23 21:29:101564 EXPECT_EQ(0, static_cast<int>(ping_data[1].diff_error_category));
sorin30474f02017-04-27 00:45:481565 EXPECT_EQ(0, ping_data[1].diff_error_code);
Minh X. Nguyena4640cb2018-05-23 21:29:101566 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:481567 EXPECT_EQ(0, ping_data[1].error_code);
sorin9797aba2015-04-17 17:15:031568 }
1569 };
1570
sorin30474f02017-04-27 00:45:481571 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431572 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531573 config(), base::MakeRefCounted<MockPingManager>(config()),
1574 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031575
1576 MockObserver observer;
1577 {
1578 InSequence seq;
1579 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1580 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1581 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1582 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1583 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481584 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1585 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031586 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1587 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1588 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1589 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1590 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1591 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1592 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1593 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1594 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481595 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1596 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031597 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1598 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1599 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1600 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1601 }
1602
1603 update_client->AddObserver(&observer);
1604
sorin30474f02017-04-27 00:45:481605 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031606 {
1607 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531608 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271609 false,
Sorin Jianua8926bf2018-03-09 21:02:531610 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171611 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031612 runloop.Run();
1613 }
1614
1615 {
1616 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:531617 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:271618 false,
Sorin Jianua8926bf2018-03-09 21:02:531619 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:171620 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031621 runloop.Run();
1622 }
1623
1624 update_client->RemoveObserver(&observer);
1625}
1626
1627// Tests the update scenario for one CRX where the CRX installer returns
Sorin Jianuf40ab4b32017-10-06 22:53:411628// an error. Tests that the |unpack_path| argument refers to a valid path
1629// then |Install| is called, then tests that the |unpack| path is deleted
1630// by the |update_client| code before the test ends.
sorin9797aba2015-04-17 17:15:031631TEST_F(UpdateClientTest, OneCrxInstallError) {
1632 class MockInstaller : public CrxInstaller {
1633 public:
1634 MOCK_METHOD1(OnUpdateError, void(int error));
Sorin Jianua8ef73d2017-11-02 16:55:171635 MOCK_METHOD2(DoInstall,
Sorin Jianu7aa6d1f2017-10-13 20:29:291636 void(const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:411637 const Callback& callback));
sorin9797aba2015-04-17 17:15:031638 MOCK_METHOD2(GetInstalledFile,
1639 bool(const std::string& file, base::FilePath* installed_file));
1640 MOCK_METHOD0(Uninstall, bool());
1641
Sorin Jianua8ef73d2017-11-02 16:55:171642 void Install(const base::FilePath& unpack_path,
1643 const std::string& public_key,
Daniel Cheng67848522018-04-27 22:04:411644 Callback callback) override {
Sorin Jianua8ef73d2017-11-02 16:55:171645 DoInstall(unpack_path, std::move(callback));
1646
Sorin Jianu23f70f752017-05-30 16:21:581647 unpack_path_ = unpack_path;
1648 EXPECT_TRUE(base::DirectoryExists(unpack_path_));
Sorin Jianuf40ab4b32017-10-06 22:53:411649 base::PostTaskWithTraits(
1650 FROM_HERE, {base::MayBlock()},
Sorin Jianua8ef73d2017-11-02 16:55:171651 base::BindOnce(std::move(callback),
Sorin Jianuf40ab4b32017-10-06 22:53:411652 CrxInstaller::Result(InstallError::GENERIC_ERROR)));
sorin9797aba2015-04-17 17:15:031653 }
1654
1655 protected:
Sorin Jianu23f70f752017-05-30 16:21:581656 ~MockInstaller() override {
1657 // The unpack path is deleted unconditionally by the component state code,
1658 // which is driving this installer. Therefore, the unpack path must not
1659 // exist when this object is destroyed.
1660 if (!unpack_path_.empty())
1661 EXPECT_FALSE(base::DirectoryExists(unpack_path_));
1662 }
1663
1664 private:
1665 // Contains the |unpack_path| argument of the Install call.
1666 base::FilePath unpack_path_;
sorin9797aba2015-04-17 17:15:031667 };
1668
Sorin Jianua8926bf2018-03-09 21:02:531669 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031670 public:
Sorin Jianu7c22795b2018-04-26 22:16:521671 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1672 const std::vector<std::string>& ids) {
sorin30474f02017-04-27 00:45:481673 scoped_refptr<MockInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431674 base::MakeRefCounted<MockInstaller>();
sorin9797aba2015-04-17 17:15:031675
1676 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
Sorin Jianua8ef73d2017-11-02 16:55:171677 EXPECT_CALL(*installer, DoInstall(_, _)).Times(1);
sorin9797aba2015-04-17 17:15:031678 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
1679 EXPECT_CALL(*installer, Uninstall()).Times(0);
1680
Sorin Jianu7c22795b2018-04-26 22:16:521681 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1682 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:241683 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521684 crx->version = base::Version("0.9");
1685 crx->installer = installer;
1686
1687 std::vector<std::unique_ptr<CrxComponent>> component;
1688 component.push_back(std::move(crx));
1689 return component;
sorin9797aba2015-04-17 17:15:031690 }
1691 };
1692
Sorin Jianua8926bf2018-03-09 21:02:531693 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031694 public:
Sorin Jianua8ef73d2017-11-02 16:55:171695 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411696 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171697 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031698 }
1699 };
1700
Sorin Jianua8926bf2018-03-09 21:02:531701 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031702 public:
dchengd0fc6aa92016-04-22 18:03:121703 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421704 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491705 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531706 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031707 }
1708
Sorin Jianud69d4372018-02-07 19:44:221709 void CheckForUpdates(const std::string& session_id,
1710 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171711 const IdToComponentPtrMap& components,
1712 const std::string& additional_attributes,
1713 bool enabled_component_updates,
1714 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:031715 /*
Sorin Jianua8926bf2018-03-09 21:02:531716 Mock the following response:
sorin9797aba2015-04-17 17:15:031717
1718 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281719 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031720 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1721 <updatecheck status='ok'>
1722 <urls>
1723 <url codebase='http://localhost/download/'/>
1724 </urls>
1725 <manifest version='1.0' prodversionmin='11.0.1.0'>
1726 <packages>
sorin74e70672016-02-03 03:13:101727 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
1728 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
1729 7c9b12cb7cc067667bde87'/>
sorin9797aba2015-04-17 17:15:031730 </packages>
1731 </manifest>
1732 </updatecheck>
1733 </app>
1734 </response>
1735 */
Sorin Jianud69d4372018-02-07 19:44:221736 EXPECT_FALSE(session_id.empty());
1737
sorin30474f02017-04-27 00:45:481738 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
1739 EXPECT_EQ(id, ids_to_check[0]);
1740 EXPECT_EQ(1u, components.count(id));
1741
sorin7cff6e52017-05-17 16:37:231742 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031743 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101744 package.hash_sha256 =
1745 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin30474f02017-04-27 00:45:481746
sorin7cff6e52017-05-17 16:37:231747 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481748 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171749 result.status = "ok";
sorin9797aba2015-04-17 17:15:031750 result.crx_urls.push_back(GURL("http://localhost/download/"));
1751 result.manifest.version = "1.0";
1752 result.manifest.browser_min_version = "11.0.1.0";
1753 result.manifest.packages.push_back(package);
1754
Sorin Jianu888ec292018-06-01 15:35:421755 ProtocolParser::Results results;
1756 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031757 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461758 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1759 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:031760 }
1761 };
1762
Sorin Jianua8926bf2018-03-09 21:02:531763 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031764 public:
dchengd0fc6aa92016-04-22 18:03:121765 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031766 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:211767 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:531768 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031769 }
1770
Sorin Jianua8926bf2018-03-09 21:02:531771 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031772
sorin30474f02017-04-27 00:45:481773 private:
sorin9797aba2015-04-17 17:15:031774 void DoStartDownload(const GURL& url) override {
1775 DownloadMetrics download_metrics;
1776 download_metrics.url = url;
1777 download_metrics.downloader = DownloadMetrics::kNone;
1778 download_metrics.error = 0;
1779 download_metrics.downloaded_bytes = 1843;
1780 download_metrics.total_bytes = 1843;
1781 download_metrics.download_time_ms = 1000;
1782
1783 FilePath path;
1784 EXPECT_TRUE(MakeTestFile(
1785 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1786
1787 Result result;
1788 result.error = 0;
1789 result.response = path;
1790 result.downloaded_bytes = 1843;
1791 result.total_bytes = 1843;
1792
1793 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531794 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianua8ef73d2017-11-02 16:55:171795 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:031796
1797 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531798 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581799 base::Unretained(this), true, result,
1800 download_metrics));
sorin9797aba2015-04-17 17:15:031801 }
1802 };
1803
Sorin Jianua8926bf2018-03-09 21:02:531804 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031805 public:
Sorin Jianua8926bf2018-03-09 21:02:531806 explicit MockPingManager(scoped_refptr<Configurator> config)
1807 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541808
1809 protected:
Sorin Jianua8926bf2018-03-09 21:02:531810 ~MockPingManager() override {
1811 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481812 EXPECT_EQ(1u, ping_data.size());
1813 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1814 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1815 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101816 EXPECT_EQ(3, static_cast<int>(ping_data[0].error_category)); // kInstall.
1817 EXPECT_EQ(9, ping_data[0].error_code); // kInstallerError.
sorin9797aba2015-04-17 17:15:031818 }
1819 };
1820
sorin30474f02017-04-27 00:45:481821 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431822 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531823 config(), base::MakeRefCounted<MockPingManager>(config()),
1824 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031825
1826 MockObserver observer;
1827 {
1828 InSequence seq;
1829 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1830 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1831 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1832 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1833 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481834 "jebgalgnebhfojomionfpkfelancnnkf"))
1835 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031836 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1837 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
Sorin Jianucbb10e12018-01-23 18:01:441838 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1839 "jebgalgnebhfojomionfpkfelancnnkf"))
1840 .Times(1);
sorin9797aba2015-04-17 17:15:031841 }
1842
1843 update_client->AddObserver(&observer);
1844
sorin30474f02017-04-27 00:45:481845 std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:031846 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:531847 ids, base::BindOnce(&DataCallbackMock::Callback), false,
1848 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031849
1850 RunThreads();
1851
1852 update_client->RemoveObserver(&observer);
1853}
1854
1855// Tests the fallback from differential to full update scenario for one CRX.
1856TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
Sorin Jianua8926bf2018-03-09 21:02:531857 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031858 public:
Sorin Jianu7c22795b2018-04-26 22:16:521859 static std::vector<std::unique_ptr<CrxComponent>> Callback(
1860 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:031861 static int num_calls = 0;
1862
1863 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:481864 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431865 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:031866
1867 ++num_calls;
1868
Sorin Jianu7c22795b2018-04-26 22:16:521869 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
1870 crx->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:241871 crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:521872 crx->installer = installer;
sorin9797aba2015-04-17 17:15:031873 if (num_calls == 1) {
Sorin Jianu7c22795b2018-04-26 22:16:521874 crx->version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031875 } else if (num_calls == 2) {
Sorin Jianu7c22795b2018-04-26 22:16:521876 crx->version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031877 } else {
1878 NOTREACHED();
1879 }
1880
Sorin Jianu7c22795b2018-04-26 22:16:521881 std::vector<std::unique_ptr<CrxComponent>> component;
1882 component.push_back(std::move(crx));
1883 return component;
sorin9797aba2015-04-17 17:15:031884 }
1885 };
1886
Sorin Jianua8926bf2018-03-09 21:02:531887 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031888 public:
Sorin Jianua8ef73d2017-11-02 16:55:171889 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411890 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171891 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031892 }
1893 };
1894
Sorin Jianua8926bf2018-03-09 21:02:531895 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031896 public:
dchengd0fc6aa92016-04-22 18:03:121897 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421898 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491899 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531900 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031901 }
1902
Sorin Jianud69d4372018-02-07 19:44:221903 void CheckForUpdates(const std::string& session_id,
1904 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:171905 const IdToComponentPtrMap& components,
1906 const std::string& additional_attributes,
1907 bool enabled_component_updates,
1908 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:221909 EXPECT_FALSE(session_id.empty());
1910
sorin9797aba2015-04-17 17:15:031911 static int num_call = 0;
1912 ++num_call;
1913
sorin7cff6e52017-05-17 16:37:231914 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:031915
1916 if (num_call == 1) {
1917 /*
Sorin Jianua8926bf2018-03-09 21:02:531918 Mock the following response:
sorin9797aba2015-04-17 17:15:031919 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281920 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031921 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1922 <updatecheck status='ok'>
1923 <urls>
1924 <url codebase='http://localhost/download/'/>
1925 </urls>
1926 <manifest version='1.0' prodversionmin='11.0.1.0'>
1927 <packages>
sorin74e70672016-02-03 03:13:101928 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1929 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
sorin30474f02017-04-27 00:45:481930 3f309f156ea6d27229c0b3f9'
1931 fp='1'/>
sorin9797aba2015-04-17 17:15:031932 </packages>
1933 </manifest>
1934 </updatecheck>
1935 </app>
1936 </response>
1937 */
sorin30474f02017-04-27 00:45:481938 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1939 EXPECT_EQ(id, ids_to_check[0]);
1940 EXPECT_EQ(1u, components.count(id));
1941
sorin7cff6e52017-05-17 16:37:231942 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031943 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101944 package.hash_sha256 =
1945 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
sorin9797aba2015-04-17 17:15:031946 package.fingerprint = "1";
sorin30474f02017-04-27 00:45:481947
sorin7cff6e52017-05-17 16:37:231948 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481949 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171950 result.status = "ok";
sorin9797aba2015-04-17 17:15:031951 result.crx_urls.push_back(GURL("http://localhost/download/"));
1952 result.manifest.version = "1.0";
1953 result.manifest.browser_min_version = "11.0.1.0";
1954 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421955 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031956 } else if (num_call == 2) {
1957 /*
Sorin Jianua8926bf2018-03-09 21:02:531958 Mock the following response:
sorin9797aba2015-04-17 17:15:031959 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281960 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031961 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1962 <updatecheck status='ok'>
1963 <urls>
1964 <url codebase='http://localhost/download/'/>
1965 <url codebasediff='http://localhost/download/'/>
1966 </urls>
1967 <manifest version='2.0' prodversionmin='11.0.1.0'>
1968 <packages>
1969 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1970 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
sorin74e70672016-02-03 03:13:101971 hash_sha256='1af337fbd19c72db0f870753bcd7711c3ae9dcaa
1972 0ecde26c262bad942b112990'
1973 fp='22'
1974 hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
sorin46bdd0b32016-08-30 22:42:261975 8ead3686290c94792658ec06f2f2'/>
sorin9797aba2015-04-17 17:15:031976 </packages>
1977 </manifest>
1978 </updatecheck>
1979 </app>
1980 </response>
1981 */
sorin30474f02017-04-27 00:45:481982 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1983 EXPECT_EQ(id, ids_to_check[0]);
1984 EXPECT_EQ(1u, components.count(id));
1985
sorin7cff6e52017-05-17 16:37:231986 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031987 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1988 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101989 package.hash_sha256 =
1990 "1af337fbd19c72db0f870753bcd7711c3ae9dcaa0ecde26c262bad942b112990";
1991 package.hashdiff_sha256 =
1992 "73c6e2d4f783fc4ca5481e89e0b8bfce7aec8ead3686290c94792658ec06f2f2";
sorin9797aba2015-04-17 17:15:031993 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:481994
sorin7cff6e52017-05-17 16:37:231995 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481996 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171997 result.status = "ok";
sorin9797aba2015-04-17 17:15:031998 result.crx_urls.push_back(GURL("http://localhost/download/"));
1999 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
2000 result.manifest.version = "2.0";
2001 result.manifest.browser_min_version = "11.0.1.0";
2002 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:422003 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:032004 } else {
2005 NOTREACHED();
2006 }
2007
2008 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462009 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2010 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:032011 }
2012 };
2013
Sorin Jianua8926bf2018-03-09 21:02:532014 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:032015 public:
dchengd0fc6aa92016-04-22 18:03:122016 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:032017 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212018 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532019 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:032020 }
2021
Sorin Jianua8926bf2018-03-09 21:02:532022 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:032023
sorin30474f02017-04-27 00:45:482024 private:
sorin9797aba2015-04-17 17:15:032025 void DoStartDownload(const GURL& url) override {
2026 DownloadMetrics download_metrics;
2027 FilePath path;
2028 Result result;
2029 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
2030 download_metrics.url = url;
2031 download_metrics.downloader = DownloadMetrics::kNone;
2032 download_metrics.error = 0;
2033 download_metrics.downloaded_bytes = 53638;
2034 download_metrics.total_bytes = 53638;
2035 download_metrics.download_time_ms = 2000;
2036
2037 EXPECT_TRUE(MakeTestFile(
2038 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
2039
2040 result.error = 0;
2041 result.response = path;
2042 result.downloaded_bytes = 53638;
2043 result.total_bytes = 53638;
2044 } else if (url.path() ==
2045 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
2046 // A download error is injected on this execution path.
2047 download_metrics.url = url;
2048 download_metrics.downloader = DownloadMetrics::kNone;
2049 download_metrics.error = -1;
2050 download_metrics.downloaded_bytes = 0;
2051 download_metrics.total_bytes = 2105;
2052 download_metrics.download_time_ms = 1000;
2053
Sorin Jianu52de5fa2017-10-09 23:19:332054 // The response must not include a file path in the case of errors.
sorin9797aba2015-04-17 17:15:032055 result.error = -1;
sorin9797aba2015-04-17 17:15:032056 result.downloaded_bytes = 0;
2057 result.total_bytes = 2105;
2058 } else if (url.path() ==
2059 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
2060 download_metrics.url = url;
2061 download_metrics.downloader = DownloadMetrics::kNone;
2062 download_metrics.error = 0;
2063 download_metrics.downloaded_bytes = 53855;
2064 download_metrics.total_bytes = 53855;
2065 download_metrics.download_time_ms = 1000;
2066
2067 EXPECT_TRUE(MakeTestFile(
2068 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
2069
2070 result.error = 0;
2071 result.response = path;
2072 result.downloaded_bytes = 53855;
2073 result.total_bytes = 53855;
2074 }
2075
2076 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532077 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:582078 base::Unretained(this), result));
sorin9797aba2015-04-17 17:15:032079
2080 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532081 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582082 base::Unretained(this), true, result,
2083 download_metrics));
sorin9797aba2015-04-17 17:15:032084 }
2085 };
2086
Sorin Jianua8926bf2018-03-09 21:02:532087 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:032088 public:
Sorin Jianua8926bf2018-03-09 21:02:532089 explicit MockPingManager(scoped_refptr<Configurator> config)
2090 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542091
2092 protected:
Sorin Jianua8926bf2018-03-09 21:02:532093 ~MockPingManager() override {
2094 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482095 EXPECT_EQ(2u, ping_data.size());
2096 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
2097 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
2098 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102099 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:482100 EXPECT_EQ(0, ping_data[0].error_code);
2101 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
2102 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
2103 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102104 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:482105 EXPECT_EQ(0, ping_data[1].error_code);
2106 EXPECT_TRUE(ping_data[1].diff_update_failed);
Minh X. Nguyena4640cb2018-05-23 21:29:102107 EXPECT_EQ(1, static_cast<int>(ping_data[1].diff_error_category));
sorin30474f02017-04-27 00:45:482108 EXPECT_EQ(-1, ping_data[1].diff_error_code);
sorin9797aba2015-04-17 17:15:032109 }
2110 };
2111
sorin30474f02017-04-27 00:45:482112 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432113 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532114 config(), base::MakeRefCounted<MockPingManager>(config()),
2115 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:032116
2117 MockObserver observer;
2118 {
2119 InSequence seq;
2120 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2121 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2122 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2123 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2124 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482125 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2126 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:032127 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2128 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2129 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2130 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2131
2132 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2133 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2134 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2135 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2136 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482137 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2138 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:032139 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2140 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2141 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2142 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2143 }
2144
2145 update_client->AddObserver(&observer);
2146
sorin30474f02017-04-27 00:45:482147 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:032148
2149 {
2150 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532151 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272152 false,
Sorin Jianua8926bf2018-03-09 21:02:532153 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172154 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:032155 runloop.Run();
2156 }
2157
2158 {
2159 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532160 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272161 false,
Sorin Jianua8926bf2018-03-09 21:02:532162 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172163 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:032164 runloop.Run();
2165 }
2166
2167 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:092168}
2169
2170// Tests the queuing of update checks. In this scenario, two update checks are
2171// done for one CRX. The second update check call is queued up and will run
2172// after the first check has completed. The CRX has no updates.
2173TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
Sorin Jianua8926bf2018-03-09 21:02:532174 class DataCallbackMock {
sorin7c717622015-05-26 19:59:092175 public:
Sorin Jianu7c22795b2018-04-26 22:16:522176 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2177 const std::vector<std::string>& ids) {
2178 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2179 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242180 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522181 crx->version = base::Version("0.9");
2182 crx->installer = base::MakeRefCounted<TestInstaller>();
2183 std::vector<std::unique_ptr<CrxComponent>> component;
2184 component.push_back(std::move(crx));
2185 return component;
sorin7c717622015-05-26 19:59:092186 }
2187 };
2188
Sorin Jianua8926bf2018-03-09 21:02:532189 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:092190 public:
Sorin Jianua8ef73d2017-11-02 16:55:172191 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7c717622015-05-26 19:59:092192 static int num_call = 0;
2193 ++num_call;
2194
sorin7b8650522016-11-02 18:23:412195 EXPECT_EQ(Error::NONE, error);
sorin7c717622015-05-26 19:59:092196
2197 if (num_call == 2)
Sorin Jianua8ef73d2017-11-02 16:55:172198 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:092199 }
2200 };
2201
Sorin Jianua8926bf2018-03-09 21:02:532202 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:092203 public:
dchengd0fc6aa92016-04-22 18:03:122204 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422205 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492206 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532207 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:092208 }
2209
Sorin Jianud69d4372018-02-07 19:44:222210 void CheckForUpdates(const std::string& session_id,
2211 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172212 const IdToComponentPtrMap& components,
2213 const std::string& additional_attributes,
2214 bool enabled_component_updates,
2215 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222216 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482217 EXPECT_TRUE(enabled_component_updates);
2218 EXPECT_EQ(1u, ids_to_check.size());
2219 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2220 EXPECT_EQ(id, ids_to_check.front());
2221 EXPECT_EQ(1u, components.count(id));
2222
2223 auto& component = components.at(id);
2224
Sorin Jianub41a592a2018-03-02 16:30:272225 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:482226
sorin7cff6e52017-05-17 16:37:232227 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482228 result.extension_id = id;
2229 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:422230 ProtocolParser::Results results;
2231 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482232
sorin7c717622015-05-26 19:59:092233 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462234 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2235 ErrorCategory::kNone, 0, 0));
sorin7c717622015-05-26 19:59:092236 }
2237 };
2238
Sorin Jianua8926bf2018-03-09 21:02:532239 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092240 public:
dchengd0fc6aa92016-04-22 18:03:122241 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092242 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212243 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532244 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092245 }
2246
Sorin Jianua8926bf2018-03-09 21:02:532247 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092248
sorin30474f02017-04-27 00:45:482249 private:
sorin7c717622015-05-26 19:59:092250 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2251 };
2252
Sorin Jianua8926bf2018-03-09 21:02:532253 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092254 public:
Sorin Jianua8926bf2018-03-09 21:02:532255 explicit MockPingManager(scoped_refptr<Configurator> config)
2256 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542257
2258 protected:
Sorin Jianua8926bf2018-03-09 21:02:532259 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin7c717622015-05-26 19:59:092260 };
2261
sorin30474f02017-04-27 00:45:482262 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432263 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532264 config(), base::MakeRefCounted<MockPingManager>(config()),
2265 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:092266
2267 MockObserver observer;
2268 InSequence seq;
2269 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2270 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2271 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2272 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2273 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2274 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2275 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2276 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2277
2278 update_client->AddObserver(&observer);
2279
sorin30474f02017-04-27 00:45:482280 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin7c717622015-05-26 19:59:092281 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532282 ids, base::BindOnce(&DataCallbackMock::Callback), false,
2283 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092284 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532285 ids, base::BindOnce(&DataCallbackMock::Callback), false,
2286 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092287
2288 RunThreads();
2289
2290 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:092291}
2292
2293// Tests the install of one CRX.
2294TEST_F(UpdateClientTest, OneCrxInstall) {
Sorin Jianua8926bf2018-03-09 21:02:532295 class DataCallbackMock {
sorin7c717622015-05-26 19:59:092296 public:
Sorin Jianu7c22795b2018-04-26 22:16:522297 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2298 const std::vector<std::string>& ids) {
2299 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2300 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242301 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522302 crx->version = base::Version("0.0");
2303 crx->installer = base::MakeRefCounted<TestInstaller>();
sorin7c717622015-05-26 19:59:092304
Sorin Jianu7c22795b2018-04-26 22:16:522305 std::vector<std::unique_ptr<CrxComponent>> component;
2306 component.push_back(std::move(crx));
2307 return component;
sorin7c717622015-05-26 19:59:092308 }
2309 };
2310
Sorin Jianua8926bf2018-03-09 21:02:532311 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:092312 public:
Sorin Jianua8ef73d2017-11-02 16:55:172313 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:412314 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172315 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:092316 }
2317 };
2318
Sorin Jianua8926bf2018-03-09 21:02:532319 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:092320 public:
dchengd0fc6aa92016-04-22 18:03:122321 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422322 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492323 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532324 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:092325 }
2326
Sorin Jianud69d4372018-02-07 19:44:222327 void CheckForUpdates(const std::string& session_id,
2328 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172329 const IdToComponentPtrMap& components,
2330 const std::string& additional_attributes,
2331 bool enabled_component_updates,
2332 UpdateCheckCallback update_check_callback) override {
sorin7c717622015-05-26 19:59:092333 /*
Sorin Jianua8926bf2018-03-09 21:02:532334 Mock the following response:
sorin7c717622015-05-26 19:59:092335
2336 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282337 <response protocol='3.1'>
sorin7c717622015-05-26 19:59:092338 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2339 <updatecheck status='ok'>
2340 <urls>
2341 <url codebase='http://localhost/download/'/>
2342 </urls>
2343 <manifest version='1.0' prodversionmin='11.0.1.0'>
2344 <packages>
sorin74e70672016-02-03 03:13:102345 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
2346 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
2347 7c9b12cb7cc067667bde87'/>
sorin7c717622015-05-26 19:59:092348 </packages>
2349 </manifest>
2350 </updatecheck>
2351 </app>
2352 </response>
2353 */
Sorin Jianud69d4372018-02-07 19:44:222354 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482355 EXPECT_TRUE(enabled_component_updates);
2356 EXPECT_EQ(1u, ids_to_check.size());
2357
2358 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2359 EXPECT_EQ(id, ids_to_check[0]);
2360 EXPECT_EQ(1u, components.count(id));
2361
sorin7cff6e52017-05-17 16:37:232362 ProtocolParser::Result::Manifest::Package package;
sorin7c717622015-05-26 19:59:092363 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:102364 package.hash_sha256 =
2365 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorin30474f02017-04-27 00:45:482366
sorin7cff6e52017-05-17 16:37:232367 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482368 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:172369 result.status = "ok";
sorin7c717622015-05-26 19:59:092370 result.crx_urls.push_back(GURL("http://localhost/download/"));
2371 result.manifest.version = "1.0";
2372 result.manifest.browser_min_version = "11.0.1.0";
2373 result.manifest.packages.push_back(package);
2374
Sorin Jianu888ec292018-06-01 15:35:422375 ProtocolParser::Results results;
2376 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482377
2378 // Verify that calling Install sets ondemand.
Sorin Jianu888ec292018-06-01 15:35:422379 EXPECT_TRUE(components.at(id)->is_foreground());
sorin7c717622015-05-26 19:59:092380
2381 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462382 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2383 ErrorCategory::kNone, 0, 0));
sorin7c717622015-05-26 19:59:092384 }
2385 };
2386
Sorin Jianua8926bf2018-03-09 21:02:532387 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092388 public:
dchengd0fc6aa92016-04-22 18:03:122389 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092390 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212391 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532392 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092393 }
2394
Sorin Jianua8926bf2018-03-09 21:02:532395 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092396
sorin30474f02017-04-27 00:45:482397 private:
sorin7c717622015-05-26 19:59:092398 void DoStartDownload(const GURL& url) override {
2399 DownloadMetrics download_metrics;
2400 FilePath path;
2401 Result result;
2402 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
2403 download_metrics.url = url;
2404 download_metrics.downloader = DownloadMetrics::kNone;
2405 download_metrics.error = 0;
2406 download_metrics.downloaded_bytes = 1843;
2407 download_metrics.total_bytes = 1843;
2408 download_metrics.download_time_ms = 1000;
2409
2410 EXPECT_TRUE(MakeTestFile(
2411 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
2412
2413 result.error = 0;
2414 result.response = path;
2415 result.downloaded_bytes = 1843;
2416 result.total_bytes = 1843;
2417 } else {
2418 NOTREACHED();
2419 }
2420
2421 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532422 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:582423 base::Unretained(this), result));
sorin7c717622015-05-26 19:59:092424
2425 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532426 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582427 base::Unretained(this), true, result,
2428 download_metrics));
sorin7c717622015-05-26 19:59:092429 }
2430 };
2431
Sorin Jianua8926bf2018-03-09 21:02:532432 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092433 public:
Sorin Jianua8926bf2018-03-09 21:02:532434 explicit MockPingManager(scoped_refptr<Configurator> config)
2435 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542436
2437 protected:
Sorin Jianua8926bf2018-03-09 21:02:532438 ~MockPingManager() override {
2439 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482440 EXPECT_EQ(1u, ping_data.size());
2441 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
2442 EXPECT_EQ(base::Version("0.0"), ping_data[0].previous_version);
2443 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102444 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:482445 EXPECT_EQ(0, ping_data[0].error_code);
sorin7c717622015-05-26 19:59:092446 }
2447 };
2448
sorin30474f02017-04-27 00:45:482449 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432450 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532451 config(), base::MakeRefCounted<MockPingManager>(config()),
2452 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:092453
2454 MockObserver observer;
sorin7c717622015-05-26 19:59:092455 InSequence seq;
2456 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2457 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2458 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2459 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2460 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482461 "jebgalgnebhfojomionfpkfelancnnkf"))
2462 .Times(AtLeast(1));
sorin7c717622015-05-26 19:59:092463 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2464 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2465 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2466 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2467
2468 update_client->AddObserver(&observer);
2469
2470 update_client->Install(
2471 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532472 base::BindOnce(&DataCallbackMock::Callback),
2473 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092474
2475 RunThreads();
2476
2477 update_client->RemoveObserver(&observer);
sorin9797aba2015-04-17 17:15:032478}
2479
Sorin Jianucb4431a2018-04-30 20:59:242480// Tests the install of one CRX when no component data is provided. This
2481// results in an install error.
2482TEST_F(UpdateClientTest, OneCrxInstallNoCrxComponentData) {
2483 class DataCallbackMock {
2484 public:
2485 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2486 const std::vector<std::string>& ids) {
2487 std::vector<std::unique_ptr<CrxComponent>> component;
2488 component.push_back(nullptr);
2489 return component;
2490 }
2491 };
2492
2493 class CompletionCallbackMock {
2494 public:
2495 static void Callback(base::OnceClosure quit_closure, Error error) {
2496 EXPECT_EQ(Error::NONE, error);
2497 std::move(quit_closure).Run();
2498 }
2499 };
2500
2501 class MockUpdateChecker : public UpdateChecker {
2502 public:
2503 static std::unique_ptr<UpdateChecker> Create(
2504 scoped_refptr<Configurator> config,
2505 PersistedData* metadata) {
2506 return std::make_unique<MockUpdateChecker>();
2507 }
2508
2509 void CheckForUpdates(const std::string& session_id,
2510 const std::vector<std::string>& ids_to_check,
2511 const IdToComponentPtrMap& components,
2512 const std::string& additional_attributes,
2513 bool enabled_component_updates,
2514 UpdateCheckCallback update_check_callback) override {
2515 NOTREACHED();
2516 }
2517 };
2518
2519 class MockCrxDownloader : public CrxDownloader {
2520 public:
2521 static std::unique_ptr<CrxDownloader> Create(
2522 bool is_background_download,
2523 scoped_refptr<net::URLRequestContextGetter> context_getter) {
2524 return std::make_unique<MockCrxDownloader>();
2525 }
2526
2527 MockCrxDownloader() : CrxDownloader(nullptr) {}
2528
2529 private:
2530 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
2531 };
2532
2533 class MockPingManager : public MockPingManagerImpl {
2534 public:
2535 explicit MockPingManager(scoped_refptr<Configurator> config)
2536 : MockPingManagerImpl(config) {}
2537
2538 protected:
2539 ~MockPingManager() override {
2540 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
2541 }
2542 };
2543
2544 scoped_refptr<UpdateClient> update_client =
2545 base::MakeRefCounted<UpdateClientImpl>(
2546 config(), base::MakeRefCounted<MockPingManager>(config()),
2547 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
2548
2549 MockObserver observer;
2550 InSequence seq;
2551 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
2552 "jebgalgnebhfojomionfpkfelancnnkf"))
2553 .Times(1);
2554
2555 update_client->AddObserver(&observer);
2556
2557 update_client->Install(
2558 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2559 base::BindOnce(&DataCallbackMock::Callback),
2560 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
2561
2562 RunThreads();
2563
2564 update_client->RemoveObserver(&observer);
2565}
2566
sorin08d153c2015-10-30 00:04:202567// Tests that overlapping installs of the same CRX result in an error.
2568TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
Sorin Jianua8926bf2018-03-09 21:02:532569 class DataCallbackMock {
sorin08d153c2015-10-30 00:04:202570 public:
Sorin Jianu7c22795b2018-04-26 22:16:522571 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2572 const std::vector<std::string>& ids) {
2573 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2574 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242575 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522576 crx->version = base::Version("0.0");
2577 crx->installer = base::MakeRefCounted<TestInstaller>();
2578 std::vector<std::unique_ptr<CrxComponent>> component;
2579 component.push_back(std::move(crx));
2580 return component;
sorin08d153c2015-10-30 00:04:202581 }
2582 };
2583
Sorin Jianua8926bf2018-03-09 21:02:532584 class CompletionCallbackMock {
sorin08d153c2015-10-30 00:04:202585 public:
Sorin Jianua8ef73d2017-11-02 16:55:172586 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin08d153c2015-10-30 00:04:202587 static int num_call = 0;
2588 ++num_call;
2589
2590 EXPECT_LE(num_call, 2);
2591
2592 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412593 EXPECT_EQ(Error::UPDATE_IN_PROGRESS, error);
sorin08d153c2015-10-30 00:04:202594 return;
2595 }
2596 if (num_call == 2) {
sorin7b8650522016-11-02 18:23:412597 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172598 std::move(quit_closure).Run();
sorin08d153c2015-10-30 00:04:202599 }
2600 }
2601 };
2602
Sorin Jianua8926bf2018-03-09 21:02:532603 class MockUpdateChecker : public UpdateChecker {
sorin08d153c2015-10-30 00:04:202604 public:
dchengd0fc6aa92016-04-22 18:03:122605 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422606 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492607 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532608 return std::make_unique<MockUpdateChecker>();
sorin08d153c2015-10-30 00:04:202609 }
2610
Sorin Jianud69d4372018-02-07 19:44:222611 void CheckForUpdates(const std::string& session_id,
2612 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172613 const IdToComponentPtrMap& components,
2614 const std::string& additional_attributes,
2615 bool enabled_component_updates,
2616 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222617 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482618 EXPECT_TRUE(enabled_component_updates);
2619 EXPECT_EQ(1u, ids_to_check.size());
2620 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2621 EXPECT_EQ(id, ids_to_check.front());
2622 EXPECT_EQ(1u, components.count(id));
2623
sorin7cff6e52017-05-17 16:37:232624 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482625 result.extension_id = id;
2626 result.status = "noupdate";
2627
Sorin Jianu888ec292018-06-01 15:35:422628 ProtocolParser::Results results;
2629 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482630
Sorin Jianub41a592a2018-03-02 16:30:272631 // Verify that calling Install sets |is_foreground| for the component.
Sorin Jianu888ec292018-06-01 15:35:422632 EXPECT_TRUE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:482633
sorin08d153c2015-10-30 00:04:202634 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462635 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2636 ErrorCategory::kNone, 0, 0));
sorin08d153c2015-10-30 00:04:202637 }
2638 };
2639
Sorin Jianua8926bf2018-03-09 21:02:532640 class MockCrxDownloader : public CrxDownloader {
sorin08d153c2015-10-30 00:04:202641 public:
dchengd0fc6aa92016-04-22 18:03:122642 static std::unique_ptr<CrxDownloader> Create(
sorin08d153c2015-10-30 00:04:202643 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212644 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532645 return std::make_unique<MockCrxDownloader>();
sorin08d153c2015-10-30 00:04:202646 }
2647
Sorin Jianua8926bf2018-03-09 21:02:532648 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin08d153c2015-10-30 00:04:202649
sorin30474f02017-04-27 00:45:482650 private:
sorin08d153c2015-10-30 00:04:202651 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2652 };
2653
Sorin Jianua8926bf2018-03-09 21:02:532654 class MockPingManager : public MockPingManagerImpl {
sorin08d153c2015-10-30 00:04:202655 public:
Sorin Jianua8926bf2018-03-09 21:02:532656 explicit MockPingManager(scoped_refptr<Configurator> config)
2657 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542658
2659 protected:
Sorin Jianua8926bf2018-03-09 21:02:532660 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin08d153c2015-10-30 00:04:202661 };
2662
sorin30474f02017-04-27 00:45:482663 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432664 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532665 config(), base::MakeRefCounted<MockPingManager>(config()),
2666 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin08d153c2015-10-30 00:04:202667
2668 MockObserver observer;
sorin08d153c2015-10-30 00:04:202669 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2670 "jebgalgnebhfojomionfpkfelancnnkf"))
2671 .Times(1);
2672 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2673 "jebgalgnebhfojomionfpkfelancnnkf"))
2674 .Times(1);
2675
2676 update_client->AddObserver(&observer);
2677
2678 update_client->Install(
2679 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532680 base::BindOnce(&DataCallbackMock::Callback),
2681 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:202682
2683 update_client->Install(
2684 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532685 base::BindOnce(&DataCallbackMock::Callback),
2686 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:202687
2688 RunThreads();
2689
2690 update_client->RemoveObserver(&observer);
sorin08d153c2015-10-30 00:04:202691}
2692
sorin30474f02017-04-27 00:45:482693// Tests that UpdateClient::Update returns Error::INVALID_ARGUMENT when
2694// the |ids| parameter is empty.
asargente90363b2015-09-09 22:40:072695TEST_F(UpdateClientTest, EmptyIdList) {
Sorin Jianua8926bf2018-03-09 21:02:532696 class DataCallbackMock {
asargente90363b2015-09-09 22:40:072697 public:
Sorin Jianu7c22795b2018-04-26 22:16:522698 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2699 const std::vector<std::string>& ids) {
2700 return {};
2701 }
asargente90363b2015-09-09 22:40:072702 };
2703
Sorin Jianua8926bf2018-03-09 21:02:532704 class CompletionCallbackMock {
asargente90363b2015-09-09 22:40:072705 public:
Sorin Jianua8ef73d2017-11-02 16:55:172706 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin30474f02017-04-27 00:45:482707 DCHECK_EQ(Error::INVALID_ARGUMENT, error);
Sorin Jianua8ef73d2017-11-02 16:55:172708 std::move(quit_closure).Run();
asargente90363b2015-09-09 22:40:072709 }
2710 };
sorin30474f02017-04-27 00:45:482711
Sorin Jianua8926bf2018-03-09 21:02:532712 class MockUpdateChecker : public UpdateChecker {
asargente90363b2015-09-09 22:40:072713 public:
dchengd0fc6aa92016-04-22 18:03:122714 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422715 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492716 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532717 return std::make_unique<MockUpdateChecker>();
asargente90363b2015-09-09 22:40:072718 }
2719
Sorin Jianud69d4372018-02-07 19:44:222720 void CheckForUpdates(const std::string& session_id,
2721 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172722 const IdToComponentPtrMap& components,
2723 const std::string& additional_attributes,
2724 bool enabled_component_updates,
Sorin Jianud69d4372018-02-07 19:44:222725 UpdateCheckCallback update_check_callback) override {
2726 NOTREACHED();
2727 }
asargente90363b2015-09-09 22:40:072728 };
2729
Sorin Jianua8926bf2018-03-09 21:02:532730 class MockCrxDownloader : public CrxDownloader {
asargente90363b2015-09-09 22:40:072731 public:
dchengd0fc6aa92016-04-22 18:03:122732 static std::unique_ptr<CrxDownloader> Create(
asargente90363b2015-09-09 22:40:072733 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212734 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532735 return std::make_unique<MockCrxDownloader>();
asargente90363b2015-09-09 22:40:072736 }
2737
Sorin Jianua8926bf2018-03-09 21:02:532738 MockCrxDownloader() : CrxDownloader(nullptr) {}
asargente90363b2015-09-09 22:40:072739
sorin30474f02017-04-27 00:45:482740 private:
asargente90363b2015-09-09 22:40:072741 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2742 };
2743
Sorin Jianua8926bf2018-03-09 21:02:532744 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu560d5022018-02-12 23:11:542745 public:
Sorin Jianua8926bf2018-03-09 21:02:532746 explicit MockPingManager(scoped_refptr<Configurator> config)
2747 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542748
2749 protected:
Sorin Jianua8926bf2018-03-09 21:02:532750 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
Sorin Jianu560d5022018-02-12 23:11:542751 };
2752
sorin30474f02017-04-27 00:45:482753 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432754 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532755 config(), base::MakeRefCounted<MockPingManager>(config()),
2756 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
asargente90363b2015-09-09 22:40:072757
sorin30474f02017-04-27 00:45:482758 const std::vector<std::string> empty_id_list;
asargente90363b2015-09-09 22:40:072759 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:532760 empty_id_list, base::BindOnce(&DataCallbackMock::Callback), false,
2761 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin30474f02017-04-27 00:45:482762 RunThreads();
asargente90363b2015-09-09 22:40:072763}
2764
sorin805aa03112016-01-14 23:01:312765TEST_F(UpdateClientTest, SendUninstallPing) {
Sorin Jianua8926bf2018-03-09 21:02:532766 class CompletionCallbackMock {
sorin8037ac8c2017-04-19 16:28:002767 public:
Sorin Jianua8ef73d2017-11-02 16:55:172768 static void Callback(base::OnceClosure quit_closure, Error error) {
2769 std::move(quit_closure).Run();
sorin8037ac8c2017-04-19 16:28:002770 }
2771 };
2772
Sorin Jianua8926bf2018-03-09 21:02:532773 class MockUpdateChecker : public UpdateChecker {
sorin805aa03112016-01-14 23:01:312774 public:
dchengd0fc6aa92016-04-22 18:03:122775 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422776 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492777 PersistedData* metadata) {
sorin805aa03112016-01-14 23:01:312778 return nullptr;
2779 }
2780
Sorin Jianud69d4372018-02-07 19:44:222781 void CheckForUpdates(const std::string& session_id,
2782 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172783 const IdToComponentPtrMap& components,
2784 const std::string& additional_attributes,
2785 bool enabled_component_updates,
Sorin Jianud69d4372018-02-07 19:44:222786 UpdateCheckCallback update_check_callback) override {
2787 NOTREACHED();
2788 }
sorin805aa03112016-01-14 23:01:312789 };
2790
Sorin Jianua8926bf2018-03-09 21:02:532791 class MockCrxDownloader : public CrxDownloader {
sorin805aa03112016-01-14 23:01:312792 public:
dchengd0fc6aa92016-04-22 18:03:122793 static std::unique_ptr<CrxDownloader> Create(
sorin805aa03112016-01-14 23:01:312794 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212795 scoped_refptr<net::URLRequestContextGetter> context_getter) {
sorin805aa03112016-01-14 23:01:312796 return nullptr;
2797 }
2798
2799 private:
Sorin Jianua8926bf2018-03-09 21:02:532800 MockCrxDownloader() : CrxDownloader(nullptr) {}
2801 ~MockCrxDownloader() override {}
sorin805aa03112016-01-14 23:01:312802
2803 void DoStartDownload(const GURL& url) override {}
2804 };
2805
Sorin Jianua8926bf2018-03-09 21:02:532806 class MockPingManager : public MockPingManagerImpl {
sorin805aa03112016-01-14 23:01:312807 public:
Sorin Jianua8926bf2018-03-09 21:02:532808 explicit MockPingManager(scoped_refptr<Configurator> config)
2809 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542810
2811 protected:
Sorin Jianua8926bf2018-03-09 21:02:532812 ~MockPingManager() override {
2813 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482814 EXPECT_EQ(1u, ping_data.size());
2815 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
Minh X. Nguyen01d3586d2018-01-03 21:53:392816 EXPECT_EQ(base::Version("1.2.3.4"), ping_data[0].previous_version);
2817 EXPECT_EQ(base::Version("0"), ping_data[0].next_version);
sorin30474f02017-04-27 00:45:482818 EXPECT_EQ(10, ping_data[0].extra_code1);
sorin805aa03112016-01-14 23:01:312819 }
2820 };
2821
sorin30474f02017-04-27 00:45:482822 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432823 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532824 config(), base::MakeRefCounted<MockPingManager>(config()),
2825 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin805aa03112016-01-14 23:01:312826
sorin8037ac8c2017-04-19 16:28:002827 update_client->SendUninstallPing(
Minh X. Nguyen01d3586d2018-01-03 21:53:392828 "jebgalgnebhfojomionfpkfelancnnkf", base::Version("1.2.3.4"), 10,
Sorin Jianua8926bf2018-03-09 21:02:532829 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin8037ac8c2017-04-19 16:28:002830
2831 RunThreads();
sorin805aa03112016-01-14 23:01:312832}
2833
sorinfccbf2d2016-04-04 20:34:342834TEST_F(UpdateClientTest, RetryAfter) {
Sorin Jianua8926bf2018-03-09 21:02:532835 class DataCallbackMock {
sorinfccbf2d2016-04-04 20:34:342836 public:
Sorin Jianu7c22795b2018-04-26 22:16:522837 static std::vector<std::unique_ptr<CrxComponent>> Callback(
2838 const std::vector<std::string>& ids) {
2839 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
2840 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:242841 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:522842 crx->version = base::Version("0.9");
2843 crx->installer = base::MakeRefCounted<TestInstaller>();
2844 std::vector<std::unique_ptr<CrxComponent>> component;
2845 component.push_back(std::move(crx));
2846 return component;
sorinfccbf2d2016-04-04 20:34:342847 }
2848 };
2849
Sorin Jianua8926bf2018-03-09 21:02:532850 class CompletionCallbackMock {
sorinfccbf2d2016-04-04 20:34:342851 public:
Sorin Jianua8ef73d2017-11-02 16:55:172852 static void Callback(base::OnceClosure quit_closure, Error error) {
sorinfccbf2d2016-04-04 20:34:342853 static int num_call = 0;
2854 ++num_call;
2855
2856 EXPECT_LE(num_call, 4);
2857
2858 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412859 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342860 } else if (num_call == 2) {
2861 // This request is throttled since the update engine received a
2862 // positive |retry_after_sec| value in the update check response.
sorin7b8650522016-11-02 18:23:412863 EXPECT_EQ(Error::RETRY_LATER, error);
sorinfccbf2d2016-04-04 20:34:342864 } else if (num_call == 3) {
2865 // This request is a foreground Install, which is never throttled.
2866 // The update engine received a |retry_after_sec| value of 0, which
2867 // resets the throttling.
sorin7b8650522016-11-02 18:23:412868 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342869 } else if (num_call == 4) {
2870 // This request succeeds since there is no throttling in effect.
sorin7b8650522016-11-02 18:23:412871 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:342872 }
2873
Sorin Jianua8ef73d2017-11-02 16:55:172874 std::move(quit_closure).Run();
sorinfccbf2d2016-04-04 20:34:342875 }
2876 };
2877
Sorin Jianua8926bf2018-03-09 21:02:532878 class MockUpdateChecker : public UpdateChecker {
sorinfccbf2d2016-04-04 20:34:342879 public:
dchengd0fc6aa92016-04-22 18:03:122880 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422881 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492882 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532883 return std::make_unique<MockUpdateChecker>();
sorinfccbf2d2016-04-04 20:34:342884 }
2885
Sorin Jianud69d4372018-02-07 19:44:222886 void CheckForUpdates(const std::string& session_id,
2887 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:172888 const IdToComponentPtrMap& components,
2889 const std::string& additional_attributes,
2890 bool enabled_component_updates,
2891 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222892 EXPECT_FALSE(session_id.empty());
2893
sorinfccbf2d2016-04-04 20:34:342894 static int num_call = 0;
2895 ++num_call;
2896
2897 EXPECT_LE(num_call, 3);
2898
2899 int retry_after_sec(0);
2900 if (num_call == 1) {
2901 // Throttle the next call.
2902 retry_after_sec = 60 * 60; // 1 hour.
2903 }
2904
sorin30474f02017-04-27 00:45:482905 EXPECT_EQ(1u, ids_to_check.size());
2906 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2907 EXPECT_EQ(id, ids_to_check.front());
2908 EXPECT_EQ(1u, components.count(id));
2909
sorin7cff6e52017-05-17 16:37:232910 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482911 result.extension_id = id;
2912 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:422913
2914 ProtocolParser::Results results;
2915 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482916
sorinfccbf2d2016-04-04 20:34:342917 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462918 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2919 ErrorCategory::kNone, 0, retry_after_sec));
sorinfccbf2d2016-04-04 20:34:342920 }
2921 };
2922
Sorin Jianua8926bf2018-03-09 21:02:532923 class MockCrxDownloader : public CrxDownloader {
sorinfccbf2d2016-04-04 20:34:342924 public:
dchengd0fc6aa92016-04-22 18:03:122925 static std::unique_ptr<CrxDownloader> Create(
sorinfccbf2d2016-04-04 20:34:342926 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:212927 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:532928 return std::make_unique<MockCrxDownloader>();
sorinfccbf2d2016-04-04 20:34:342929 }
2930
Sorin Jianua8926bf2018-03-09 21:02:532931 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorinfccbf2d2016-04-04 20:34:342932
sorin30474f02017-04-27 00:45:482933 private:
sorinfccbf2d2016-04-04 20:34:342934 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2935 };
2936
Sorin Jianua8926bf2018-03-09 21:02:532937 class MockPingManager : public MockPingManagerImpl {
sorinfccbf2d2016-04-04 20:34:342938 public:
Sorin Jianua8926bf2018-03-09 21:02:532939 explicit MockPingManager(scoped_refptr<Configurator> config)
2940 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542941
2942 protected:
Sorin Jianua8926bf2018-03-09 21:02:532943 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorinfccbf2d2016-04-04 20:34:342944 };
2945
sorin30474f02017-04-27 00:45:482946 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432947 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532948 config(), base::MakeRefCounted<MockPingManager>(config()),
2949 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorinfccbf2d2016-04-04 20:34:342950
2951 MockObserver observer;
2952
2953 InSequence seq;
2954 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2955 "jebgalgnebhfojomionfpkfelancnnkf"))
2956 .Times(1);
2957 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2958 "jebgalgnebhfojomionfpkfelancnnkf"))
2959 .Times(1);
2960 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2961 "jebgalgnebhfojomionfpkfelancnnkf"))
2962 .Times(1);
2963 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2964 "jebgalgnebhfojomionfpkfelancnnkf"))
2965 .Times(1);
2966 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2967 "jebgalgnebhfojomionfpkfelancnnkf"))
2968 .Times(1);
2969 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2970 "jebgalgnebhfojomionfpkfelancnnkf"))
2971 .Times(1);
2972
2973 update_client->AddObserver(&observer);
2974
sorin30474f02017-04-27 00:45:482975 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorinfccbf2d2016-04-04 20:34:342976 {
2977 // The engine handles this Update call but responds with a valid
2978 // |retry_after_sec|, which causes subsequent calls to fail.
2979 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532980 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272981 false,
Sorin Jianua8926bf2018-03-09 21:02:532982 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172983 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342984 runloop.Run();
2985 }
2986
2987 {
2988 // This call will result in a completion callback invoked with
2989 // Error::ERROR_UPDATE_RETRY_LATER.
2990 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:532991 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:272992 false,
Sorin Jianua8926bf2018-03-09 21:02:532993 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:172994 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:342995 runloop.Run();
2996 }
2997
2998 {
2999 // The Install call is handled, and the throttling is reset due to
3000 // the value of |retry_after_sec| in the completion callback.
3001 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:173002 update_client->Install(std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:533003 base::BindOnce(&DataCallbackMock::Callback),
3004 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173005 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343006 runloop.Run();
3007 }
3008
3009 {
3010 // This call succeeds.
3011 base::RunLoop runloop;
Sorin Jianua8926bf2018-03-09 21:02:533012 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianub41a592a2018-03-02 16:30:273013 false,
Sorin Jianua8926bf2018-03-09 21:02:533014 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173015 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343016 runloop.Run();
3017 }
3018
3019 update_client->RemoveObserver(&observer);
3020}
3021
sorine84ff702016-08-04 01:22:023022// Tests the update check for two CRXs scenario. The first component supports
3023// the group policy to enable updates, and has its updates disabled. The second
3024// component has an update. The server does not honor the "updatedisabled"
sorin30474f02017-04-27 00:45:483025// attribute and returns updates for both components. However, the update for
Sorin Jianu888ec292018-06-01 15:35:423026// the first component is not applied and the client responds with a
sorin30474f02017-04-27 00:45:483027// (SERVICE_ERROR, UPDATE_DISABLED)
sorine84ff702016-08-04 01:22:023028TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
Sorin Jianua8926bf2018-03-09 21:02:533029 class DataCallbackMock {
sorine84ff702016-08-04 01:22:023030 public:
Sorin Jianu7c22795b2018-04-26 22:16:523031 static std::vector<std::unique_ptr<CrxComponent>> Callback(
3032 const std::vector<std::string>& ids) {
3033 std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
3034 crx1->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:243035 crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523036 crx1->version = base::Version("0.9");
3037 crx1->installer = base::MakeRefCounted<TestInstaller>();
3038 crx1->supports_group_policy_enable_component_updates = true;
sorine84ff702016-08-04 01:22:023039
Sorin Jianu7c22795b2018-04-26 22:16:523040 std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
3041 crx2->name = "test_ihfo";
Sorin Jianucb4431a2018-04-30 20:59:243042 crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523043 crx2->version = base::Version("0.8");
3044 crx2->installer = base::MakeRefCounted<TestInstaller>();
sorine84ff702016-08-04 01:22:023045
Sorin Jianu7c22795b2018-04-26 22:16:523046 std::vector<std::unique_ptr<CrxComponent>> component;
3047 component.push_back(std::move(crx1));
3048 component.push_back(std::move(crx2));
3049 return component;
sorine84ff702016-08-04 01:22:023050 }
3051 };
3052
Sorin Jianua8926bf2018-03-09 21:02:533053 class CompletionCallbackMock {
sorine84ff702016-08-04 01:22:023054 public:
Sorin Jianua8ef73d2017-11-02 16:55:173055 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:413056 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173057 std::move(quit_closure).Run();
sorine84ff702016-08-04 01:22:023058 }
3059 };
3060
Sorin Jianua8926bf2018-03-09 21:02:533061 class MockUpdateChecker : public UpdateChecker {
sorine84ff702016-08-04 01:22:023062 public:
3063 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423064 scoped_refptr<Configurator> config,
sorine84ff702016-08-04 01:22:023065 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533066 return std::make_unique<MockUpdateChecker>();
sorine84ff702016-08-04 01:22:023067 }
3068
Sorin Jianud69d4372018-02-07 19:44:223069 void CheckForUpdates(const std::string& session_id,
3070 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173071 const IdToComponentPtrMap& components,
3072 const std::string& additional_attributes,
3073 bool enabled_component_updates,
3074 UpdateCheckCallback update_check_callback) override {
sorine84ff702016-08-04 01:22:023075 /*
Sorin Jianua8926bf2018-03-09 21:02:533076 Mock the following response:
sorine84ff702016-08-04 01:22:023077
3078 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:283079 <response protocol='3.1'>
sorine84ff702016-08-04 01:22:023080 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
3081 <updatecheck status='ok'>
3082 <urls>
3083 <url codebase='http://localhost/download/'/>
3084 </urls>
3085 <manifest version='1.0' prodversionmin='11.0.1.0'>
3086 <packages>
3087 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
3088 hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
3089 7c9b12cb7cc067667bde87'/>
3090 </packages>
3091 </manifest>
3092 </updatecheck>
3093 </app>
3094 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
3095 <updatecheck status='ok'>
3096 <urls>
3097 <url codebase='http://localhost/download/'/>
3098 </urls>
3099 <manifest version='1.0' prodversionmin='11.0.1.0'>
3100 <packages>
3101 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
3102 hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
3103 309f156ea6d27229c0b3f9'/>
3104 </packages>
3105 </manifest>
3106 </updatecheck>
3107 </app>
3108 </response>
3109 */
sorin590921d2016-08-11 23:48:363110
3111 // UpdateClient reads the state of |enabled_component_updates| from the
3112 // configurator instance, persists its value in the corresponding
3113 // update context, and propagates it down to each of the update actions,
3114 // and further down to the UpdateChecker instance.
Sorin Jianud69d4372018-02-07 19:44:223115 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:363116 EXPECT_FALSE(enabled_component_updates);
sorin30474f02017-04-27 00:45:483117 EXPECT_EQ(2u, ids_to_check.size());
sorine84ff702016-08-04 01:22:023118
Sorin Jianu888ec292018-06-01 15:35:423119 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:483120 {
3121 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3122 EXPECT_EQ(id, ids_to_check[0]);
3123 EXPECT_EQ(1u, components.count(id));
sorine84ff702016-08-04 01:22:023124
sorin7cff6e52017-05-17 16:37:233125 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:483126 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
3127 package.hash_sha256 =
3128 "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
sorine84ff702016-08-04 01:22:023129
sorin7cff6e52017-05-17 16:37:233130 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:483131 result.extension_id = id;
3132 result.status = "ok";
3133 result.crx_urls.push_back(GURL("http://localhost/download/"));
3134 result.manifest.version = "1.0";
3135 result.manifest.browser_min_version = "11.0.1.0";
3136 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:423137 results.list.push_back(result);
sorin30474f02017-04-27 00:45:483138 }
3139
3140 {
3141 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
3142 EXPECT_EQ(id, ids_to_check[1]);
3143 EXPECT_EQ(1u, components.count(id));
3144
sorin7cff6e52017-05-17 16:37:233145 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:483146 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
3147 package.hash_sha256 =
3148 "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
3149
sorin7cff6e52017-05-17 16:37:233150 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:483151 result.extension_id = id;
3152 result.status = "ok";
3153 result.crx_urls.push_back(GURL("http://localhost/download/"));
3154 result.manifest.version = "1.0";
3155 result.manifest.browser_min_version = "11.0.1.0";
3156 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:423157 results.list.push_back(result);
sorin30474f02017-04-27 00:45:483158 }
sorine84ff702016-08-04 01:22:023159
3160 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:463161 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
3162 ErrorCategory::kNone, 0, 0));
sorine84ff702016-08-04 01:22:023163 }
3164 };
3165
Sorin Jianua8926bf2018-03-09 21:02:533166 class MockCrxDownloader : public CrxDownloader {
sorine84ff702016-08-04 01:22:023167 public:
3168 static std::unique_ptr<CrxDownloader> Create(
3169 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213170 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533171 return std::make_unique<MockCrxDownloader>();
sorine84ff702016-08-04 01:22:023172 }
3173
Sorin Jianua8926bf2018-03-09 21:02:533174 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorine84ff702016-08-04 01:22:023175
sorin30474f02017-04-27 00:45:483176 private:
sorine84ff702016-08-04 01:22:023177 void DoStartDownload(const GURL& url) override {
3178 DownloadMetrics download_metrics;
3179 FilePath path;
3180 Result result;
3181 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
3182 download_metrics.url = url;
3183 download_metrics.downloader = DownloadMetrics::kNone;
3184 download_metrics.error = 0;
3185 download_metrics.downloaded_bytes = 53638;
3186 download_metrics.total_bytes = 53638;
3187 download_metrics.download_time_ms = 2000;
3188
3189 EXPECT_TRUE(MakeTestFile(
3190 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
3191
3192 result.error = 0;
3193 result.response = path;
3194 result.downloaded_bytes = 53638;
3195 result.total_bytes = 53638;
3196 } else {
3197 NOTREACHED();
3198 }
3199
3200 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533201 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Sorin Jianuebd652462017-07-23 02:00:583202 base::Unretained(this), result));
sorine84ff702016-08-04 01:22:023203
3204 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533205 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:583206 base::Unretained(this), true, result,
3207 download_metrics));
sorine84ff702016-08-04 01:22:023208 }
3209 };
3210
Sorin Jianua8926bf2018-03-09 21:02:533211 class MockPingManager : public MockPingManagerImpl {
sorine84ff702016-08-04 01:22:023212 public:
Sorin Jianua8926bf2018-03-09 21:02:533213 explicit MockPingManager(scoped_refptr<Configurator> config)
3214 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543215
3216 protected:
Sorin Jianua8926bf2018-03-09 21:02:533217 ~MockPingManager() override {
3218 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:483219 EXPECT_EQ(2u, ping_data.size());
3220 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
3221 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
3222 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:103223 EXPECT_EQ(4, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:483224 EXPECT_EQ(2, ping_data[0].error_code);
3225 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
3226 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
3227 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:103228 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:483229 EXPECT_EQ(0, ping_data[1].error_code);
sorine84ff702016-08-04 01:22:023230 }
3231 };
3232
3233 // Disables updates for the components declaring support for the group policy.
3234 config()->SetEnabledComponentUpdates(false);
sorin30474f02017-04-27 00:45:483235 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433236 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533237 config(), base::MakeRefCounted<MockPingManager>(config()),
3238 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorine84ff702016-08-04 01:22:023239
3240 MockObserver observer;
3241 {
3242 InSequence seq;
3243 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3244 "jebgalgnebhfojomionfpkfelancnnkf"))
3245 .Times(1);
3246 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3247 "jebgalgnebhfojomionfpkfelancnnkf"))
3248 .Times(1);
Sorin Jianucbb10e12018-01-23 18:01:443249 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorine84ff702016-08-04 01:22:023250 "jebgalgnebhfojomionfpkfelancnnkf"))
3251 .Times(1);
3252 }
3253 {
3254 InSequence seq;
3255 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3256 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3257 .Times(1);
3258 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3259 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3260 .Times(1);
sorine84ff702016-08-04 01:22:023261 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
3262 "ihfokbkgjpifnbbojhneepfflplebdkc"))
sorin30474f02017-04-27 00:45:483263 .Times(AtLeast(1));
sorine84ff702016-08-04 01:22:023264 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
3265 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3266 .Times(1);
3267 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
3268 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3269 .Times(1);
3270 }
3271
3272 update_client->AddObserver(&observer);
3273
sorin30474f02017-04-27 00:45:483274 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
3275 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorine84ff702016-08-04 01:22:023276 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:533277 ids, base::BindOnce(&DataCallbackMock::Callback), false,
3278 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorine84ff702016-08-04 01:22:023279
3280 RunThreads();
3281
3282 update_client->RemoveObserver(&observer);
3283}
3284
sorin03ec5b72017-05-01 23:14:243285// Tests the scenario where the update check fails.
3286TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
Sorin Jianua8926bf2018-03-09 21:02:533287 class DataCallbackMock {
sorin03ec5b72017-05-01 23:14:243288 public:
Sorin Jianu7c22795b2018-04-26 22:16:523289 static std::vector<std::unique_ptr<CrxComponent>> Callback(
3290 const std::vector<std::string>& ids) {
3291 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
3292 crx->name = "test_jebg";
Sorin Jianucb4431a2018-04-30 20:59:243293 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523294 crx->version = base::Version("0.9");
3295 crx->installer = base::MakeRefCounted<TestInstaller>();
3296 std::vector<std::unique_ptr<CrxComponent>> component;
3297 component.push_back(std::move(crx));
3298 return component;
sorin03ec5b72017-05-01 23:14:243299 }
3300 };
3301
Sorin Jianua8926bf2018-03-09 21:02:533302 class CompletionCallbackMock {
sorin03ec5b72017-05-01 23:14:243303 public:
Sorin Jianua8ef73d2017-11-02 16:55:173304 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin03ec5b72017-05-01 23:14:243305 EXPECT_EQ(Error::UPDATE_CHECK_ERROR, error);
Sorin Jianua8ef73d2017-11-02 16:55:173306 std::move(quit_closure).Run();
sorin03ec5b72017-05-01 23:14:243307 }
3308 };
3309
Sorin Jianua8926bf2018-03-09 21:02:533310 class MockUpdateChecker : public UpdateChecker {
sorin03ec5b72017-05-01 23:14:243311 public:
3312 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423313 scoped_refptr<Configurator> config,
sorin03ec5b72017-05-01 23:14:243314 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533315 return std::make_unique<MockUpdateChecker>();
sorin03ec5b72017-05-01 23:14:243316 }
3317
Sorin Jianud69d4372018-02-07 19:44:223318 void CheckForUpdates(const std::string& session_id,
3319 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173320 const IdToComponentPtrMap& components,
3321 const std::string& additional_attributes,
3322 bool enabled_component_updates,
3323 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223324 EXPECT_FALSE(session_id.empty());
sorin03ec5b72017-05-01 23:14:243325 EXPECT_TRUE(enabled_component_updates);
3326 EXPECT_EQ(1u, ids_to_check.size());
3327 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3328 EXPECT_EQ(id, ids_to_check.front());
3329 EXPECT_EQ(1u, components.count(id));
sorin03ec5b72017-05-01 23:14:243330 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianu888ec292018-06-01 15:35:423331 FROM_HERE,
3332 base::BindOnce(std::move(update_check_callback), base::nullopt,
3333 ErrorCategory::kUpdateCheck, -1, 0));
sorin03ec5b72017-05-01 23:14:243334 }
3335 };
3336
Sorin Jianua8926bf2018-03-09 21:02:533337 class MockCrxDownloader : public CrxDownloader {
sorin03ec5b72017-05-01 23:14:243338 public:
3339 static std::unique_ptr<CrxDownloader> Create(
3340 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213341 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533342 return std::make_unique<MockCrxDownloader>();
sorin03ec5b72017-05-01 23:14:243343 }
3344
Sorin Jianua8926bf2018-03-09 21:02:533345 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin03ec5b72017-05-01 23:14:243346
3347 private:
3348 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3349 };
3350
Sorin Jianua8926bf2018-03-09 21:02:533351 class MockPingManager : public MockPingManagerImpl {
sorin03ec5b72017-05-01 23:14:243352 public:
Sorin Jianua8926bf2018-03-09 21:02:533353 explicit MockPingManager(scoped_refptr<Configurator> config)
3354 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543355
3356 protected:
Sorin Jianua8926bf2018-03-09 21:02:533357 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin03ec5b72017-05-01 23:14:243358 };
3359
3360 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433361 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533362 config(), base::MakeRefCounted<MockPingManager>(config()),
3363 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin03ec5b72017-05-01 23:14:243364
3365 MockObserver observer;
3366 InSequence seq;
3367 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3368 "jebgalgnebhfojomionfpkfelancnnkf"))
3369 .Times(1);
Sorin Jianucbb10e12018-01-23 18:01:443370 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorin03ec5b72017-05-01 23:14:243371 "jebgalgnebhfojomionfpkfelancnnkf"))
3372 .Times(1)
3373 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3374 CrxUpdateItem item;
3375 update_client->GetCrxUpdateState(id, &item);
3376 EXPECT_EQ(ComponentState::kUpdateError, item.state);
Minh X. Nguyena4640cb2018-05-23 21:29:103377 EXPECT_EQ(5, static_cast<int>(item.error_category));
Sorin Jianuafcb70dd2018-05-16 20:14:153378 EXPECT_EQ(-1, item.error_code);
3379 EXPECT_EQ(0, item.extra_code1);
sorin03ec5b72017-05-01 23:14:243380 }));
3381
3382 update_client->AddObserver(&observer);
3383
3384 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
3385 update_client->Update(
Sorin Jianua8926bf2018-03-09 21:02:533386 ids, base::BindOnce(&DataCallbackMock::Callback), false,
3387 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin03ec5b72017-05-01 23:14:243388
3389 RunThreads();
3390
3391 update_client->RemoveObserver(&observer);
3392}
3393
Sorin Jianuaa4165532018-06-08 19:46:463394// Tests the scenario where the server responds with different values for
3395// application status.
3396TEST_F(UpdateClientTest, OneCrxErrorUnknownApp) {
3397 class DataCallbackMock {
3398 public:
3399 static std::vector<std::unique_ptr<CrxComponent>> Callback(
3400 const std::vector<std::string>& ids) {
3401 std::vector<std::unique_ptr<CrxComponent>> component;
3402
3403 std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
3404 crx->name = "test_jebg";
3405 crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
3406 crx->version = base::Version("0.9");
3407 crx->installer = base::MakeRefCounted<TestInstaller>();
3408 component.push_back(std::move(crx));
3409
3410 crx = std::make_unique<CrxComponent>();
3411 crx->name = "test_abag";
3412 crx->pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
3413 crx->version = base::Version("0.1");
3414 crx->installer = base::MakeRefCounted<TestInstaller>();
3415 component.push_back(std::move(crx));
3416
3417 crx = std::make_unique<CrxComponent>();
3418 crx->name = "test_ihfo";
3419 crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
3420 crx->version = base::Version("0.2");
3421 crx->installer = base::MakeRefCounted<TestInstaller>();
3422 component.push_back(std::move(crx));
3423
3424 crx = std::make_unique<CrxComponent>();
3425 crx->name = "test_gjpm";
3426 crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
3427 crx->version = base::Version("0.3");
3428 crx->installer = base::MakeRefCounted<TestInstaller>();
3429 component.push_back(std::move(crx));
3430
3431 return component;
3432 }
3433 };
3434
3435 class CompletionCallbackMock {
3436 public:
3437 static void Callback(base::OnceClosure quit_closure, Error error) {
3438 EXPECT_EQ(Error::NONE, error);
3439 std::move(quit_closure).Run();
3440 }
3441 };
3442
3443 class MockUpdateChecker : public UpdateChecker {
3444 public:
3445 static std::unique_ptr<UpdateChecker> Create(
3446 scoped_refptr<Configurator> config,
3447 PersistedData* metadata) {
3448 return std::make_unique<MockUpdateChecker>();
3449 }
3450
3451 void CheckForUpdates(const std::string& session_id,
3452 const std::vector<std::string>& ids_to_check,
3453 const IdToComponentPtrMap& components,
3454 const std::string& additional_attributes,
3455 bool enabled_component_updates,
3456 UpdateCheckCallback update_check_callback) override {
3457 EXPECT_FALSE(session_id.empty());
3458 EXPECT_TRUE(enabled_component_updates);
3459 EXPECT_EQ(4u, ids_to_check.size());
3460
3461 const std::string update_response =
3462 R"(<?xml version="1.0" encoding="UTF-8"?>)"
3463 R"(<response protocol="3.1">)"
3464 R"(<app appid="jebgalgnebhfojomionfpkfelancnnkf")"
3465 R"( status="error-unknownApplication"/>)"
3466 R"(<app appid="abagagagagagagagagagagagagagagag")"
3467 R"( status="restricted"/>)"
3468 R"(<app appid="ihfokbkgjpifnbbojhneepfflplebdkc")"
3469 R"( status="error-invalidAppId"/>)"
3470 R"(<app appid="gjpmebpgbhcamgdgjcmnjfhggjpgcimm")"
3471 R"( status="error-foobarApp"/>)"
3472 R"(</response>)";
3473
3474 ProtocolParser parser;
3475 EXPECT_TRUE(parser.Parse(update_response));
3476
3477 base::ThreadTaskRunnerHandle::Get()->PostTask(
3478 FROM_HERE,
3479 base::BindOnce(std::move(update_check_callback), parser.results(),
3480 ErrorCategory::kNone, 0, 0));
3481 }
3482 };
3483
3484 class MockCrxDownloader : public CrxDownloader {
3485 public:
3486 static std::unique_ptr<CrxDownloader> Create(
3487 bool is_background_download,
3488 scoped_refptr<net::URLRequestContextGetter> context_getter) {
3489 return std::make_unique<MockCrxDownloader>();
3490 }
3491
3492 MockCrxDownloader() : CrxDownloader(nullptr) {}
3493
3494 private:
3495 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3496 };
3497
3498 class MockPingManager : public MockPingManagerImpl {
3499 public:
3500 explicit MockPingManager(scoped_refptr<Configurator> config)
3501 : MockPingManagerImpl(config) {}
3502
3503 protected:
3504 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
3505 };
3506
3507 scoped_refptr<UpdateClient> update_client =
3508 base::MakeRefCounted<UpdateClientImpl>(
3509 config(), base::MakeRefCounted<MockPingManager>(config()),
3510 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
3511
3512 MockObserver observer;
3513 {
3514 InSequence seq;
3515 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3516 "jebgalgnebhfojomionfpkfelancnnkf"))
3517 .Times(1);
3518 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3519 "jebgalgnebhfojomionfpkfelancnnkf"))
3520 .Times(1)
3521 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3522 CrxUpdateItem item;
3523 update_client->GetCrxUpdateState(id, &item);
3524 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3525 EXPECT_EQ(5, static_cast<int>(item.error_category));
3526 EXPECT_EQ(-10006, item.error_code); // UNKNOWN_APPPLICATION.
3527 EXPECT_EQ(0, item.extra_code1);
3528 }));
3529 }
3530 {
3531 InSequence seq;
3532 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3533 "abagagagagagagagagagagagagagagag"))
3534 .Times(1);
3535 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3536 "abagagagagagagagagagagagagagagag"))
3537 .Times(1)
3538 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3539 CrxUpdateItem item;
3540 update_client->GetCrxUpdateState(id, &item);
3541 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3542 EXPECT_EQ(5, static_cast<int>(item.error_category));
3543 EXPECT_EQ(-10007, item.error_code); // RESTRICTED_APPLICATION.
3544 EXPECT_EQ(0, item.extra_code1);
3545 }));
3546 }
3547 {
3548 InSequence seq;
3549 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3550 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3551 .Times(1);
3552 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3553 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3554 .Times(1)
3555 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3556 CrxUpdateItem item;
3557 update_client->GetCrxUpdateState(id, &item);
3558 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3559 EXPECT_EQ(5, static_cast<int>(item.error_category));
3560 EXPECT_EQ(-10008, item.error_code); // INVALID_APPID.
3561 EXPECT_EQ(0, item.extra_code1);
3562 }));
3563 }
3564 {
3565 InSequence seq;
3566 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3567 "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"))
3568 .Times(1);
3569 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3570 "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"))
3571 .Times(1)
3572 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3573 CrxUpdateItem item;
3574 update_client->GetCrxUpdateState(id, &item);
3575 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3576 EXPECT_EQ(5, static_cast<int>(item.error_category));
3577 EXPECT_EQ(-10004, item.error_code); // UPDATE_RESPONSE_NOT_FOUND.
3578 EXPECT_EQ(0, item.extra_code1);
3579 }));
3580 }
3581
3582 update_client->AddObserver(&observer);
3583
3584 const std::vector<std::string> ids = {
3585 "jebgalgnebhfojomionfpkfelancnnkf", "abagagagagagagagagagagagagagagag",
3586 "ihfokbkgjpifnbbojhneepfflplebdkc", "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
3587 update_client->Update(
3588 ids, base::BindOnce(&DataCallbackMock::Callback), true,
3589 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
3590
3591 RunThreads();
3592
3593 update_client->RemoveObserver(&observer);
3594}
3595
Sorin Jianu7b00a132017-06-19 21:56:543596#if defined(OS_WIN) // ActionRun is only implemented on Windows.
3597
Sorin Jianu4ab7c292017-06-15 18:40:213598// Tests that a run action in invoked in the CRX install scenario.
3599TEST_F(UpdateClientTest, ActionRun_Install) {
Sorin Jianua8926bf2018-03-09 21:02:533600 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:213601 public:
3602 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423603 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:213604 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533605 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:213606 }
3607
Sorin Jianud69d4372018-02-07 19:44:223608 void CheckForUpdates(const std::string& session_id,
3609 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173610 const IdToComponentPtrMap& components,
3611 const std::string& additional_attributes,
3612 bool enabled_component_updates,
3613 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:213614 /*
Sorin Jianua8926bf2018-03-09 21:02:533615 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:213616
3617 <?xml version='1.0' encoding='UTF-8'?>
3618 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:563619 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:213620 <updatecheck status='ok'>
3621 <urls>
3622 <url codebase='http://localhost/download/'/>
3623 </urls>
3624 <manifest version='1.0' prodversionmin='11.0.1.0'>
3625 <packages>
3626 <package name='runaction_test_win.crx3'
Sorin Jianue5bfb5b2017-06-20 21:30:563627 hash_sha256='89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea'/>
Sorin Jianu4ab7c292017-06-15 18:40:213628 </packages>
3629 </manifest>
3630 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:563631 <action run='ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:213632 </actions>"
3633 </updatecheck>
3634 </app>
3635 </response>
3636 */
Sorin Jianud69d4372018-02-07 19:44:223637 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:213638 EXPECT_TRUE(enabled_component_updates);
3639 EXPECT_EQ(1u, ids_to_check.size());
3640
Sorin Jianue5bfb5b2017-06-20 21:30:563641 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:213642 EXPECT_EQ(id, ids_to_check[0]);
3643 EXPECT_EQ(1u, components.count(id));
3644
3645 ProtocolParser::Result::Manifest::Package package;
3646 package.name = "runaction_test_win.crx3";
3647 package.hash_sha256 =
Sorin Jianue5bfb5b2017-06-20 21:30:563648 "89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea";
Sorin Jianu4ab7c292017-06-15 18:40:213649
3650 ProtocolParser::Result result;
3651 result.extension_id = id;
3652 result.status = "ok";
3653 result.crx_urls.push_back(GURL("http://localhost/download/"));
3654 result.manifest.version = "1.0";
3655 result.manifest.browser_min_version = "11.0.1.0";
3656 result.manifest.packages.push_back(package);
Sorin Jianue5bfb5b2017-06-20 21:30:563657 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:213658
Sorin Jianu888ec292018-06-01 15:35:423659 ProtocolParser::Results results;
3660 results.list.push_back(result);
Sorin Jianu4ab7c292017-06-15 18:40:213661
3662 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:463663 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
3664 ErrorCategory::kNone, 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:213665 }
3666 };
3667
Sorin Jianua8926bf2018-03-09 21:02:533668 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:213669 public:
3670 static std::unique_ptr<CrxDownloader> Create(
3671 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213672 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533673 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:213674 }
3675
Sorin Jianua8926bf2018-03-09 21:02:533676 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:213677
3678 private:
3679 void DoStartDownload(const GURL& url) override {
3680 DownloadMetrics download_metrics;
3681 FilePath path;
3682 Result result;
3683 if (url.path() == "/download/runaction_test_win.crx3") {
3684 download_metrics.url = url;
3685 download_metrics.downloader = DownloadMetrics::kNone;
3686 download_metrics.error = 0;
3687 download_metrics.downloaded_bytes = 1843;
3688 download_metrics.total_bytes = 1843;
3689 download_metrics.download_time_ms = 1000;
3690
3691 EXPECT_TRUE(
3692 MakeTestFile(TestFilePath("runaction_test_win.crx3"), &path));
3693
3694 result.error = 0;
3695 result.response = path;
3696 result.downloaded_bytes = 1843;
3697 result.total_bytes = 1843;
3698 } else {
3699 NOTREACHED();
3700 }
3701
3702 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533703 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:583704 base::Unretained(this), true, result,
3705 download_metrics));
Sorin Jianu4ab7c292017-06-15 18:40:213706 }
3707 };
3708
Sorin Jianua8926bf2018-03-09 21:02:533709 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:213710 public:
Sorin Jianua8926bf2018-03-09 21:02:533711 explicit MockPingManager(scoped_refptr<Configurator> config)
3712 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543713
3714 protected:
Sorin Jianua8926bf2018-03-09 21:02:533715 ~MockPingManager() override {
3716 const auto& events = MockPingManagerImpl::events();
Sorin Jianu4ab7c292017-06-15 18:40:213717 EXPECT_EQ(3u, events.size());
3718 EXPECT_STREQ(
3719 "<event eventtype=\"14\" eventresult=\"1\" downloader=\"unknown\" "
3720 "url=\"http://localhost/download/"
3721 "runaction_test_win.crx3\" downloaded=\"1843\" "
Minh X. Nguyen01d3586d2018-01-03 21:53:393722 "total=\"1843\" download_time_ms=\"1000\" previousversion=\"0.0\" "
3723 "nextversion=\"1.0\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213724 events[0].c_str());
3725 EXPECT_STREQ(
Sorin Jianu7b00a132017-06-19 21:56:543726 "<event eventtype=\"42\" eventresult=\"1\" "
3727 "errorcode=\"1877345072\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213728 events[1].c_str());
Minh X. Nguyen01d3586d2018-01-03 21:53:393729 EXPECT_STREQ(
3730 "<event eventtype=\"3\" eventresult=\"1\" previousversion=\"0.0\" "
3731 "nextversion=\"1.0\"/>",
3732 events[2].c_str());
Sorin Jianu4ab7c292017-06-15 18:40:213733 }
3734 };
3735
3736 scoped_refptr<UpdateClient> update_client =
3737 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533738 config(), base::MakeRefCounted<MockPingManager>(config()),
3739 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:213740
Sorin Jianu7b00a132017-06-19 21:56:543741 // The action is a program which returns 1877345072 as a hardcoded value.
Sorin Jianu4ab7c292017-06-15 18:40:213742 update_client->Install(
Sorin Jianue5bfb5b2017-06-20 21:30:563743 std::string("gjpmebpgbhcamgdgjcmnjfhggjpgcimm"),
Sorin Jianu7c22795b2018-04-26 22:16:523744 base::BindOnce([](const std::vector<std::string>& ids) {
3745 auto crx = std::make_unique<CrxComponent>();
3746 crx->name = "test_niea";
Sorin Jianucb4431a2018-04-30 20:59:243747 crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523748 crx->version = base::Version("0.0");
3749 crx->installer = base::MakeRefCounted<VersionedTestInstaller>();
3750 std::vector<std::unique_ptr<CrxComponent>> component;
3751 component.push_back(std::move(crx));
3752 return component;
Sorin Jianu4ab7c292017-06-15 18:40:213753 }),
Sorin Jianua8ef73d2017-11-02 16:55:173754 base::BindOnce(
3755 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:213756 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173757 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213758 },
3759 quit_closure()));
3760
3761 RunThreads();
3762}
3763
3764// Tests that a run action is invoked in an update scenario when there was
3765// no update.
3766TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:533767 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:213768 public:
3769 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423770 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:213771 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533772 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:213773 }
3774
Sorin Jianud69d4372018-02-07 19:44:223775 void CheckForUpdates(const std::string& session_id,
3776 const std::vector<std::string>& ids_to_check,
Sorin Jianua8ef73d2017-11-02 16:55:173777 const IdToComponentPtrMap& components,
3778 const std::string& additional_attributes,
3779 bool enabled_component_updates,
3780 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:213781 /*
Sorin Jianua8926bf2018-03-09 21:02:533782 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:213783
3784 <?xml version='1.0' encoding='UTF-8'?>
3785 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:563786 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:213787 <updatecheck status='noupdate'>
3788 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:563789 <action run=ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:213790 </actions>"
3791 </updatecheck>
3792 </app>
3793 </response>
3794 */
Sorin Jianud69d4372018-02-07 19:44:223795 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:213796 EXPECT_EQ(1u, ids_to_check.size());
Sorin Jianue5bfb5b2017-06-20 21:30:563797 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:213798 EXPECT_EQ(id, ids_to_check[0]);
3799 EXPECT_EQ(1u, components.count(id));
3800
Sorin Jianu4ab7c292017-06-15 18:40:213801 ProtocolParser::Result result;
3802 result.extension_id = id;
3803 result.status = "noupdate";
Sorin Jianue5bfb5b2017-06-20 21:30:563804 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:213805
Sorin Jianu888ec292018-06-01 15:35:423806 ProtocolParser::Results results;
3807 results.list.push_back(result);
Sorin Jianu4ab7c292017-06-15 18:40:213808
3809 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:463810 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
3811 ErrorCategory::kNone, 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:213812 }
3813 };
3814
Sorin Jianua8926bf2018-03-09 21:02:533815 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:213816 public:
3817 static std::unique_ptr<CrxDownloader> Create(
3818 bool is_background_download,
Sorin Jianu556147d2018-01-19 21:55:213819 scoped_refptr<net::URLRequestContextGetter> context_getter) {
Sorin Jianua8926bf2018-03-09 21:02:533820 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:213821 }
3822
Sorin Jianua8926bf2018-03-09 21:02:533823 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:213824
3825 private:
3826 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3827 };
3828
Sorin Jianua8926bf2018-03-09 21:02:533829 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:213830 public:
Sorin Jianua8926bf2018-03-09 21:02:533831 explicit MockPingManager(scoped_refptr<Configurator> config)
3832 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543833
3834 protected:
Sorin Jianua8926bf2018-03-09 21:02:533835 ~MockPingManager() override {
3836 const auto& events = MockPingManagerImpl::events();
Sorin Jianu4ab7c292017-06-15 18:40:213837 EXPECT_EQ(1u, events.size());
3838 EXPECT_STREQ(
Sorin Jianu7b00a132017-06-19 21:56:543839 "<event eventtype=\"42\" eventresult=\"1\" "
3840 "errorcode=\"1877345072\"/>",
Sorin Jianu4ab7c292017-06-15 18:40:213841 events[0].c_str());
3842 }
3843 };
3844
3845 // Unpack the CRX to mock an existing install to be updated. The payload to
3846 // run is going to be picked up from this directory.
3847 base::FilePath unpack_path;
3848 {
3849 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:173850 base::OnceClosure quit_closure = runloop.QuitClosure();
Sorin Jianu4ab7c292017-06-15 18:40:213851
Joshua Pawlicki6d764422018-02-21 15:23:103852 auto config = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu7c22795b2018-04-26 22:16:523853 auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
Sorin Jianue5bfb5b2017-06-20 21:30:563854 std::vector<uint8_t>(std::begin(gjpm_hash), std::end(gjpm_hash)),
Joshua Pawlicki6d764422018-02-21 15:23:103855 TestFilePath("runaction_test_win.crx3"), nullptr,
3856 config->CreateServiceManagerConnector());
Sorin Jianu4ab7c292017-06-15 18:40:213857
Sorin Jianua8ef73d2017-11-02 16:55:173858 component_unpacker->Unpack(base::BindOnce(
3859 [](base::FilePath* unpack_path, base::OnceClosure quit_closure,
Sorin Jianu4ab7c292017-06-15 18:40:213860 const ComponentUnpacker::Result& result) {
3861 EXPECT_EQ(UnpackerError::kNone, result.error);
3862 EXPECT_EQ(0, result.extended_error);
3863 *unpack_path = result.unpack_path;
Sorin Jianua8ef73d2017-11-02 16:55:173864 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213865 },
3866 &unpack_path, runloop.QuitClosure()));
3867
3868 runloop.Run();
3869 }
3870
3871 EXPECT_FALSE(unpack_path.empty());
3872 EXPECT_TRUE(base::DirectoryExists(unpack_path));
3873 int64_t file_size = 0;
Sorin Jianue5bfb5b2017-06-20 21:30:563874 EXPECT_TRUE(base::GetFileSize(unpack_path.AppendASCII("ChromeRecovery.crx3"),
3875 &file_size));
3876 EXPECT_EQ(44582, file_size);
Sorin Jianu4ab7c292017-06-15 18:40:213877
3878 base::ScopedTempDir unpack_path_owner;
3879 EXPECT_TRUE(unpack_path_owner.Set(unpack_path));
3880
3881 scoped_refptr<UpdateClient> update_client =
3882 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533883 config(), base::MakeRefCounted<MockPingManager>(config()),
3884 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:213885
Sorin Jianu7b00a132017-06-19 21:56:543886 // The action is a program which returns 1877345072 as a hardcoded value.
Sorin Jianue5bfb5b2017-06-20 21:30:563887 const std::vector<std::string> ids = {"gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
Sorin Jianu4ab7c292017-06-15 18:40:213888 update_client->Update(
3889 ids,
Sorin Jianua8ef73d2017-11-02 16:55:173890 base::BindOnce(
Sorin Jianu4ab7c292017-06-15 18:40:213891 [](const base::FilePath& unpack_path,
Sorin Jianu7c22795b2018-04-26 22:16:523892 const std::vector<std::string>& ids) {
3893 auto crx = std::make_unique<CrxComponent>();
3894 crx->name = "test_niea";
Sorin Jianucb4431a2018-04-30 20:59:243895 crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
Sorin Jianu7c22795b2018-04-26 22:16:523896 crx->version = base::Version("1.0");
3897 crx->installer =
Sorin Jianu4ab7c292017-06-15 18:40:213898 base::MakeRefCounted<ReadOnlyTestInstaller>(unpack_path);
Sorin Jianu7c22795b2018-04-26 22:16:523899 std::vector<std::unique_ptr<CrxComponent>> component;
3900 component.push_back(std::move(crx));
3901 return component;
Sorin Jianu4ab7c292017-06-15 18:40:213902 },
3903 unpack_path),
Sorin Jianub41a592a2018-03-02 16:30:273904 false,
Sorin Jianua8ef73d2017-11-02 16:55:173905 base::BindOnce(
3906 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:213907 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173908 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:213909 },
3910 quit_closure()));
3911
3912 RunThreads();
3913}
3914
Sorin Jianu7b00a132017-06-19 21:56:543915#endif // OS_WIN
3916
sorin9797aba2015-04-17 17:15:033917} // namespace update_client