blob: aa487ebcd6559e9ae8f762d5f4cc0bffb577e7ce [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"
Sorin Jianuc303bf42018-09-07 16:19:339#include "base/containers/flat_map.h"
sorin9797aba2015-04-17 17:15:0310#include "base/files/file_path.h"
11#include "base/files/file_util.h"
12#include "base/location.h"
avi5dd91f82015-12-25 22:30:4613#include "base/macros.h"
sorin9797aba2015-04-17 17:15:0314#include "base/memory/ref_counted.h"
Sorin Jianu888ec292018-06-01 15:35:4215#include "base/optional.h"
sorin9797aba2015-04-17 17:15:0316#include "base/path_service.h"
17#include "base/run_loop.h"
Sorin Jianucb4431a2018-04-30 20:59:2418#include "base/stl_util.h"
Gabriel Charette44db1422018-08-06 11:19:3319#include "base/task/post_task.h"
20#include "base/task/task_traits.h"
Gabriel Charettedd8d5985e2020-02-26 18:38:3521#include "base/task/thread_pool.h"
Sorin Jianu4ab7c292017-06-15 18:40:2122#include "base/test/scoped_path_override.h"
Gabriel Charettec7108742019-08-23 03:31:4023#include "base/test/task_environment.h"
gab7966d312016-05-11 20:35:0124#include "base/threading/thread_task_runner_handle.h"
sorin9797aba2015-04-17 17:15:0325#include "base/values.h"
26#include "base/version.h"
Sorin Jianu188907072018-01-22 18:42:2227#include "build/build_config.h"
Joshua Pawlickif4b33f382018-08-17 17:36:5128#include "components/crx_file/crx_verifier.h"
wafflesd2d9a332016-04-09 01:59:5729#include "components/prefs/testing_pref_service.h"
Sorin Jianu4ab7c292017-06-15 18:40:2130#include "components/update_client/component_unpacker.h"
sorin9797aba2015-04-17 17:15:0331#include "components/update_client/crx_update_item.h"
Sorin Jianu75e6bf22019-02-12 16:07:1232#include "components/update_client/network.h"
Joshua Pawlickid5409e12019-04-06 00:23:1133#include "components/update_client/patcher.h"
wafflesd2d9a332016-04-09 01:59:5734#include "components/update_client/persisted_data.h"
sorin9797aba2015-04-17 17:15:0335#include "components/update_client/ping_manager.h"
Joshua Pawlicki8ac39322019-04-04 21:22:4636#include "components/update_client/protocol_handler.h"
sorinb120440b2015-04-27 16:34:1537#include "components/update_client/test_configurator.h"
38#include "components/update_client/test_installer.h"
Joshua Pawlickid5409e12019-04-06 00:23:1139#include "components/update_client/unzipper.h"
sorin9797aba2015-04-17 17:15:0340#include "components/update_client/update_checker.h"
sorin7b8650522016-11-02 18:23:4141#include "components/update_client/update_client_errors.h"
sorin9797aba2015-04-17 17:15:0342#include "components/update_client/update_client_internal.h"
sorin9797aba2015-04-17 17:15:0343#include "testing/gmock/include/gmock/gmock.h"
44#include "testing/gtest/include/gtest/gtest.h"
45#include "url/gurl.h"
46
47namespace update_client {
48
49namespace {
50
51using base::FilePath;
52
53// Makes a copy of the file specified by |from_path| in a temporary directory
54// and returns the path of the copy. Returns true if successful. Cleans up if
55// there was an error creating the copy.
56bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
57 FilePath temp_dir;
58 bool result =
59 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir);
60 if (!result)
61 return false;
62
63 FilePath temp_file;
64 result = CreateTemporaryFileInDir(temp_dir, &temp_file);
65 if (!result)
66 return false;
67
68 result = CopyFile(from_path, temp_file);
69 if (!result) {
70 DeleteFile(temp_file, false);
71 return false;
72 }
73
74 *to_path = temp_file;
75 return true;
76}
77
78using Events = UpdateClient::Observer::Events;
79
80class MockObserver : public UpdateClient::Observer {
81 public:
82 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
83};
84
Sorin Jianu2fe49a02019-11-25 19:15:5685class MockActionHandler : public ActionHandler {
86 public:
87 MockActionHandler() = default;
Sorin Jianudfb12a42020-03-10 04:12:0388 MockActionHandler(const MockActionHandler&) = delete;
89 MockActionHandler& operator=(const MockActionHandler&) = delete;
Sorin Jianu2fe49a02019-11-25 19:15:5690
91 MOCK_METHOD3(Handle,
92 void(const base::FilePath&, const std::string&, Callback));
93
94 private:
95 ~MockActionHandler() override = default;
Sorin Jianudfb12a42020-03-10 04:12:0396};
Sorin Jianu2fe49a02019-11-25 19:15:5697
Sorin Jianudfb12a42020-03-10 04:12:0398class MockCrxStateChangeReceiver
99 : public base::RefCounted<MockCrxStateChangeReceiver> {
100 public:
101 MOCK_METHOD(void, Receive, (CrxUpdateItem));
102
103 private:
104 friend class base::RefCounted<MockCrxStateChangeReceiver>;
105
106 ~MockCrxStateChangeReceiver() = default;
Sorin Jianu2fe49a02019-11-25 19:15:56107};
108
sorin30474f02017-04-27 00:45:48109} // namespace
sorin7c717622015-05-26 19:59:09110
sorin30474f02017-04-27 00:45:48111using ::testing::_;
sorin30474f02017-04-27 00:45:48112using ::testing::AnyNumber;
Sorin Jianu2fe49a02019-11-25 19:15:56113using ::testing::AtLeast;
sorin30474f02017-04-27 00:45:48114using ::testing::DoAll;
115using ::testing::InSequence;
116using ::testing::Invoke;
117using ::testing::Mock;
118using ::testing::Return;
Sorin Jianu2fe49a02019-11-25 19:15:56119using ::testing::Unused;
sorin7c717622015-05-26 19:59:09120
sorin30474f02017-04-27 00:45:48121using std::string;
sorin7c717622015-05-26 19:59:09122
Sorin Jianua8926bf2018-03-09 21:02:53123class MockPingManagerImpl : public PingManager {
sorin9797aba2015-04-17 17:15:03124 public:
sorin30474f02017-04-27 00:45:48125 struct PingData {
126 std::string id;
127 base::Version previous_version;
128 base::Version next_version;
Minh X. Nguyena4640cb2018-05-23 21:29:10129 ErrorCategory error_category = ErrorCategory::kNone;
sorin30474f02017-04-27 00:45:48130 int error_code = 0;
131 int extra_code1 = 0;
Minh X. Nguyena4640cb2018-05-23 21:29:10132 ErrorCategory diff_error_category = ErrorCategory::kNone;
sorin30474f02017-04-27 00:45:48133 int diff_error_code = 0;
134 bool diff_update_failed = false;
135 };
136
Sorin Jianua8926bf2018-03-09 21:02:53137 explicit MockPingManagerImpl(scoped_refptr<Configurator> config);
sorin9797aba2015-04-17 17:15:03138
Sorin Jianu560d5022018-02-12 23:11:54139 void SendPing(const Component& component, Callback callback) override;
sorin9797aba2015-04-17 17:15:03140
sorin30474f02017-04-27 00:45:48141 const std::vector<PingData>& ping_data() const;
sorin9797aba2015-04-17 17:15:03142
Sorin Jianu039032b2018-10-12 21:48:13143 const std::vector<base::Value>& events() const;
Sorin Jianu4ab7c292017-06-15 18:40:21144
Sorin Jianu560d5022018-02-12 23:11:54145 protected:
Sorin Jianua8926bf2018-03-09 21:02:53146 ~MockPingManagerImpl() override;
Sorin Jianu560d5022018-02-12 23:11:54147
sorin9797aba2015-04-17 17:15:03148 private:
sorin30474f02017-04-27 00:45:48149 std::vector<PingData> ping_data_;
Sorin Jianu039032b2018-10-12 21:48:13150 std::vector<base::Value> events_;
Sorin Jianua8926bf2018-03-09 21:02:53151 DISALLOW_COPY_AND_ASSIGN(MockPingManagerImpl);
sorin9797aba2015-04-17 17:15:03152};
153
Sorin Jianua8926bf2018-03-09 21:02:53154MockPingManagerImpl::MockPingManagerImpl(scoped_refptr<Configurator> config)
sorin958b5d32016-01-09 02:00:20155 : PingManager(config) {}
sorin9797aba2015-04-17 17:15:03156
Sorin Jianu30881152020-03-16 14:31:19157MockPingManagerImpl::~MockPingManagerImpl() = default;
sorin9797aba2015-04-17 17:15:03158
Sorin Jianua8926bf2018-03-09 21:02:53159void MockPingManagerImpl::SendPing(const Component& component,
Sorin Jianu560d5022018-02-12 23:11:54160 Callback callback) {
sorin30474f02017-04-27 00:45:48161 PingData ping_data;
162 ping_data.id = component.id_;
163 ping_data.previous_version = component.previous_version_;
164 ping_data.next_version = component.next_version_;
165 ping_data.error_category = component.error_category_;
166 ping_data.error_code = component.error_code_;
167 ping_data.extra_code1 = component.extra_code1_;
168 ping_data.diff_error_category = component.diff_error_category_;
169 ping_data.diff_error_code = component.diff_error_code_;
170 ping_data.diff_update_failed = component.diff_update_failed();
171 ping_data_.push_back(ping_data);
Sorin Jianu4ab7c292017-06-15 18:40:21172
Sorin Jianu039032b2018-10-12 21:48:13173 events_ = component.GetEvents();
Sorin Jianu4ab7c292017-06-15 18:40:21174
Sorin Jianu560d5022018-02-12 23:11:54175 std::move(callback).Run(0, "");
sorin9797aba2015-04-17 17:15:03176}
177
Sorin Jianua8926bf2018-03-09 21:02:53178const std::vector<MockPingManagerImpl::PingData>&
179MockPingManagerImpl::ping_data() const {
sorin30474f02017-04-27 00:45:48180 return ping_data_;
sorin9797aba2015-04-17 17:15:03181}
182
Sorin Jianu039032b2018-10-12 21:48:13183const std::vector<base::Value>& MockPingManagerImpl::events() const {
Sorin Jianu4ab7c292017-06-15 18:40:21184 return events_;
185}
186
sorin9797aba2015-04-17 17:15:03187class UpdateClientTest : public testing::Test {
188 public:
189 UpdateClientTest();
190 ~UpdateClientTest() override;
191
sorin9797aba2015-04-17 17:15:03192 protected:
193 void RunThreads();
194
195 // Returns the full path to a test file.
196 static base::FilePath TestFilePath(const char* file);
197
sorine84ff702016-08-04 01:22:02198 scoped_refptr<update_client::TestConfigurator> config() { return config_; }
wafflese7dff732016-04-15 23:51:49199 update_client::PersistedData* metadata() { return metadata_.get(); }
sorin9797aba2015-04-17 17:15:03200
Sorin Jianua8ef73d2017-11-02 16:55:17201 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
sorinf9f4834d2015-04-28 17:15:02202
203 private:
sorin30474f02017-04-27 00:45:48204 static constexpr int kNumWorkerThreads_ = 2;
sorinf9f4834d2015-04-28 17:15:02205
Gabriel Charettedfa36042019-08-19 17:30:11206 base::test::TaskEnvironment task_environment_;
sorin9797aba2015-04-17 17:15:03207 base::RunLoop runloop_;
sorin9797aba2015-04-17 17:15:03208
Sorin Jianucc048f892017-07-26 02:05:54209 std::unique_ptr<TestingPrefServiceSimple> pref_ =
Jinho Bangda4e4282018-01-03 13:21:23210 std::make_unique<TestingPrefServiceSimple>();
Sorin Jianub9258672020-02-19 16:52:17211 scoped_refptr<update_client::TestConfigurator> config_ =
212 base::MakeRefCounted<TestConfigurator>(pref_.get());
213 std::unique_ptr<update_client::PersistedData> metadata_ =
214 std::make_unique<PersistedData>(pref_.get(), nullptr);
sorinf9f4834d2015-04-28 17:15:02215
sorin9797aba2015-04-17 17:15:03216 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
217};
218
sorin30474f02017-04-27 00:45:48219constexpr int UpdateClientTest::kNumWorkerThreads_;
220
Sorin Jianucc048f892017-07-26 02:05:54221UpdateClientTest::UpdateClientTest() {
wafflesd2d9a332016-04-09 01:59:57222 PersistedData::RegisterPrefs(pref_->registry());
sorin9797aba2015-04-17 17:15:03223}
224
Sorin Jianu30881152020-03-16 14:31:19225UpdateClientTest::~UpdateClientTest() = default;
sorin9797aba2015-04-17 17:15:03226
227void UpdateClientTest::RunThreads() {
228 runloop_.Run();
Gabriel Charettedfa36042019-08-19 17:30:11229 task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03230}
231
232base::FilePath UpdateClientTest::TestFilePath(const char* file) {
233 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:53234 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin9797aba2015-04-17 17:15:03235 return path.AppendASCII("components")
236 .AppendASCII("test")
237 .AppendASCII("data")
238 .AppendASCII("update_client")
239 .AppendASCII(file);
240}
241
242// Tests the scenario where one update check is done for one CRX. The CRX
243// has no update.
244TEST_F(UpdateClientTest, OneCrxNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53245 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03246 public:
Sorin Jianu73900242018-08-17 01:11:53247 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:52248 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:53249 CrxComponent crx;
250 crx.name = "test_jebg";
251 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
252 crx.version = base::Version("0.9");
253 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23254 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:53255 std::vector<base::Optional<CrxComponent>> component = {crx};
Sorin Jianu7c22795b2018-04-26 22:16:52256 return component;
sorin9797aba2015-04-17 17:15:03257 }
258 };
259
Sorin Jianua8926bf2018-03-09 21:02:53260 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03261 public:
Sorin Jianua8ef73d2017-11-02 16:55:17262 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41263 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17264 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03265 }
266 };
267
Sorin Jianua8926bf2018-03-09 21:02:53268 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03269 public:
dchengd0fc6aa92016-04-22 18:03:12270 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42271 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49272 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53273 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03274 }
275
Sorin Jianuc303bf42018-09-07 16:19:33276 void CheckForUpdates(
277 const std::string& session_id,
278 const std::vector<std::string>& ids_to_check,
279 const IdToComponentPtrMap& components,
280 const base::flat_map<std::string, std::string>& additional_attributes,
281 bool enabled_component_updates,
282 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:22283 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:36284 EXPECT_TRUE(enabled_component_updates);
sorin30474f02017-04-27 00:45:48285 EXPECT_EQ(1u, ids_to_check.size());
286 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
287 EXPECT_EQ(id, ids_to_check.front());
288 EXPECT_EQ(1u, components.count(id));
289
290 auto& component = components.at(id);
291
Sorin Jianub41a592a2018-03-02 16:30:27292 EXPECT_TRUE(component->is_foreground());
sorin30474f02017-04-27 00:45:48293
sorin7cff6e52017-05-17 16:37:23294 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48295 result.extension_id = id;
296 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:42297
298 ProtocolParser::Results results;
299 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48300
sorin9797aba2015-04-17 17:15:03301 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46302 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
303 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03304 }
305 };
306
Sorin Jianua8926bf2018-03-09 21:02:53307 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03308 public:
dchengd0fc6aa92016-04-22 18:03:12309 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03310 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:12311 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:53312 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03313 }
314
Sorin Jianua8926bf2018-03-09 21:02:53315 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03316
sorin30474f02017-04-27 00:45:48317 private:
sorin9797aba2015-04-17 17:15:03318 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
319 };
320
Sorin Jianua8926bf2018-03-09 21:02:53321 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03322 public:
Sorin Jianua8926bf2018-03-09 21:02:53323 explicit MockPingManager(scoped_refptr<Configurator> config)
324 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54325
326 protected:
Sorin Jianua8926bf2018-03-09 21:02:53327 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin9797aba2015-04-17 17:15:03328 };
329
sorin30474f02017-04-27 00:45:48330 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43331 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53332 config(), base::MakeRefCounted<MockPingManager>(config()),
333 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:09334
sorin9797aba2015-04-17 17:15:03335 MockObserver observer;
Sorin Jianudfb12a42020-03-10 04:12:03336 {
337 InSequence seq;
338 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
339 "jebgalgnebhfojomionfpkfelancnnkf"))
340 .Times(1);
341 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
342 "jebgalgnebhfojomionfpkfelancnnkf"))
343 .Times(1);
344 }
345
346 std::vector<CrxUpdateItem> items;
347 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
348 EXPECT_CALL(*receiver, Receive(_))
349 .WillRepeatedly(
350 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin9797aba2015-04-17 17:15:03351
352 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:48353 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:03354 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:03355 ids, base::BindOnce(&DataCallbackMock::Callback),
356 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver), true,
Sorin Jianua8926bf2018-03-09 21:02:53357 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03358 RunThreads();
359
Sorin Jianudfb12a42020-03-10 04:12:03360 EXPECT_EQ(2u, items.size());
361 EXPECT_EQ(ComponentState::kChecking, items[0].state);
362 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
363 EXPECT_EQ(ComponentState::kUpToDate, items[1].state);
364 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[1].id.c_str());
365
sorin9797aba2015-04-17 17:15:03366 update_client->RemoveObserver(&observer);
367}
368
369// Tests the scenario where two CRXs are checked for updates. On CRX has
370// an update, the other CRX does not.
371TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:53372 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03373 public:
Sorin Jianu73900242018-08-17 01:11:53374 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:52375 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:53376 CrxComponent crx1;
377 crx1.name = "test_jebg";
378 crx1.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
379 crx1.version = base::Version("0.9");
380 crx1.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23381 crx1.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin9797aba2015-04-17 17:15:03382
Sorin Jianu73900242018-08-17 01:11:53383 CrxComponent crx2;
384 crx2.name = "test_abag";
385 crx2.pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
386 crx2.version = base::Version("2.2");
387 crx2.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23388 crx2.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin9797aba2015-04-17 17:15:03389
Sorin Jianu73900242018-08-17 01:11:53390 return {crx1, crx2};
sorin9797aba2015-04-17 17:15:03391 }
392 };
393
Sorin Jianua8926bf2018-03-09 21:02:53394 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03395 public:
Sorin Jianua8ef73d2017-11-02 16:55:17396 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41397 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17398 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03399 }
400 };
401
Sorin Jianua8926bf2018-03-09 21:02:53402 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03403 public:
dchengd0fc6aa92016-04-22 18:03:12404 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42405 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49406 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53407 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03408 }
409
Sorin Jianuc303bf42018-09-07 16:19:33410 void CheckForUpdates(
411 const std::string& session_id,
412 const std::vector<std::string>& ids_to_check,
413 const IdToComponentPtrMap& components,
414 const base::flat_map<std::string, std::string>& additional_attributes,
415 bool enabled_component_updates,
416 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03417 /*
Sorin Jianua8926bf2018-03-09 21:02:53418 Mock the following response:
sorin9797aba2015-04-17 17:15:03419
420 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28421 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03422 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
423 <updatecheck status='ok'>
424 <urls>
425 <url codebase='http://localhost/download/'/>
426 </urls>
427 <manifest version='1.0' prodversionmin='11.0.1.0'>
428 <packages>
sorin74e70672016-02-03 03:13:10429 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:23430 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
431 a284a7cd8059c3409ce0498'/>
sorin9797aba2015-04-17 17:15:03432 </packages>
433 </manifest>
434 </updatecheck>
435 </app>
Sorin Jianu888ec292018-06-01 15:35:42436 <app appid='abagagagagagagagagagagagagagagag'>
437 <updatecheck status='noupdate'/>
438 </app>
sorin9797aba2015-04-17 17:15:03439 </response>
440 */
Sorin Jianud69d4372018-02-07 19:44:22441 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48442 EXPECT_TRUE(enabled_component_updates);
443 EXPECT_EQ(2u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03444
Sorin Jianu888ec292018-06-01 15:35:42445 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:48446 {
447 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
448 EXPECT_EQ(id, ids_to_check[0]);
449 EXPECT_EQ(1u, components.count(id));
450
sorin7cff6e52017-05-17 16:37:23451 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48452 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
453 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:23454 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
sorin30474f02017-04-27 00:45:48455
sorin7cff6e52017-05-17 16:37:23456 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48457 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
458 result.status = "ok";
459 result.crx_urls.push_back(GURL("http://localhost/download/"));
460 result.manifest.version = "1.0";
461 result.manifest.browser_min_version = "11.0.1.0";
462 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:42463 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48464
Sorin Jianu888ec292018-06-01 15:35:42465 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48466 }
467
468 {
469 const std::string id = "abagagagagagagagagagagagagagagag";
470 EXPECT_EQ(id, ids_to_check[1]);
471 EXPECT_EQ(1u, components.count(id));
472
sorin7cff6e52017-05-17 16:37:23473 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48474 result.extension_id = id;
475 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:42476 results.list.push_back(result);
sorin30474f02017-04-27 00:45:48477
Sorin Jianu888ec292018-06-01 15:35:42478 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48479 }
sorin9797aba2015-04-17 17:15:03480
481 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46482 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
483 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03484 }
485 };
486
Sorin Jianua8926bf2018-03-09 21:02:53487 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03488 public:
dchengd0fc6aa92016-04-22 18:03:12489 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03490 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:12491 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:53492 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03493 }
494
Sorin Jianua8926bf2018-03-09 21:02:53495 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03496
sorin30474f02017-04-27 00:45:48497 private:
sorin9797aba2015-04-17 17:15:03498 void DoStartDownload(const GURL& url) override {
499 DownloadMetrics download_metrics;
500 download_metrics.url = url;
501 download_metrics.downloader = DownloadMetrics::kNone;
502 download_metrics.error = 0;
503 download_metrics.downloaded_bytes = 1843;
504 download_metrics.total_bytes = 1843;
505 download_metrics.download_time_ms = 1000;
506
507 FilePath path;
508 EXPECT_TRUE(MakeTestFile(
509 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
510
511 Result result;
512 result.error = 0;
513 result.response = path;
sorin9797aba2015-04-17 17:15:03514
515 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53516 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:03517 base::Unretained(this)));
sorin9797aba2015-04-17 17:15:03518
519 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53520 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:58521 base::Unretained(this), true, result,
522 download_metrics));
sorin9797aba2015-04-17 17:15:03523 }
524 };
525
Sorin Jianua8926bf2018-03-09 21:02:53526 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03527 public:
Sorin Jianua8926bf2018-03-09 21:02:53528 explicit MockPingManager(scoped_refptr<Configurator> config)
529 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54530
531 protected:
Sorin Jianua8926bf2018-03-09 21:02:53532 ~MockPingManager() override {
533 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:48534 EXPECT_EQ(1u, ping_data.size());
535 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
536 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
537 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:10538 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:48539 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03540 }
541 };
542
sorin30474f02017-04-27 00:45:48543 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:43544 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:53545 config(), base::MakeRefCounted<MockPingManager>(config()),
546 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:03547
548 MockObserver observer;
549 {
550 InSequence seq;
551 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
552 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
553 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
554 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
555 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:48556 "jebgalgnebhfojomionfpkfelancnnkf"))
557 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:03558 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
559 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
560 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
561 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
562 }
563 {
564 InSequence seq;
565 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
566 "abagagagagagagagagagagagagagagag")).Times(1);
567 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
568 "abagagagagagagagagagagagagagagag")).Times(1);
569 }
570
Sorin Jianudfb12a42020-03-10 04:12:03571 std::vector<CrxUpdateItem> items;
572 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
573 EXPECT_CALL(*receiver, Receive(_))
574 .WillRepeatedly(
575 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin9797aba2015-04-17 17:15:03576
Sorin Jianudfb12a42020-03-10 04:12:03577 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:48578 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
579 "abagagagagagagagagagagagagagagag"};
sorin9797aba2015-04-17 17:15:03580 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:03581 ids, base::BindOnce(&DataCallbackMock::Callback),
582 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
583 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:03584 RunThreads();
585
Sorin Jianudfb12a42020-03-10 04:12:03586 EXPECT_EQ(8u, items.size());
587 EXPECT_EQ(ComponentState::kChecking, items[0].state);
588 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
589 EXPECT_EQ(ComponentState::kChecking, items[1].state);
590 EXPECT_STREQ("abagagagagagagagagagagagagagagag", items[1].id.c_str());
591 EXPECT_EQ(ComponentState::kCanUpdate, items[2].state);
592 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
593 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
594 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
595 EXPECT_EQ(ComponentState::kDownloading, items[4].state);
596 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
597 EXPECT_EQ(ComponentState::kUpdating, items[5].state);
598 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
599 EXPECT_EQ(ComponentState::kUpdated, items[6].state);
600 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[6].id.c_str());
601 EXPECT_EQ(ComponentState::kUpToDate, items[7].state);
602 EXPECT_STREQ("abagagagagagagagagagagagagagagag", items[7].id.c_str());
603
sorin9797aba2015-04-17 17:15:03604 update_client->RemoveObserver(&observer);
605}
606
Sorin Jianu888ec292018-06-01 15:35:42607// Tests the scenario where two CRXs are checked for updates. One CRX has
608// an update but the server ignores the second CRX and returns no response for
609// it. The second component gets an |UPDATE_RESPONSE_NOT_FOUND| error and
610// transitions to the error state.
611TEST_F(UpdateClientTest, TwoCrxUpdateFirstServerIgnoresSecond) {
612 class DataCallbackMock {
613 public:
Sorin Jianu73900242018-08-17 01:11:53614 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu888ec292018-06-01 15:35:42615 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:53616 CrxComponent crx1;
617 crx1.name = "test_jebg";
618 crx1.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
619 crx1.version = base::Version("0.9");
620 crx1.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23621 crx1.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu888ec292018-06-01 15:35:42622
Sorin Jianu73900242018-08-17 01:11:53623 CrxComponent crx2;
624 crx2.name = "test_abag";
625 crx2.pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
626 crx2.version = base::Version("2.2");
627 crx2.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23628 crx2.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu888ec292018-06-01 15:35:42629
Sorin Jianu73900242018-08-17 01:11:53630 return {crx1, crx2};
Sorin Jianu888ec292018-06-01 15:35:42631 }
632 };
633
634 class CompletionCallbackMock {
635 public:
636 static void Callback(base::OnceClosure quit_closure, Error error) {
637 EXPECT_EQ(Error::NONE, error);
638 std::move(quit_closure).Run();
639 }
640 };
641
642 class MockUpdateChecker : public UpdateChecker {
643 public:
644 static std::unique_ptr<UpdateChecker> Create(
645 scoped_refptr<Configurator> config,
646 PersistedData* metadata) {
647 return std::make_unique<MockUpdateChecker>();
648 }
649
Sorin Jianuc303bf42018-09-07 16:19:33650 void CheckForUpdates(
651 const std::string& session_id,
652 const std::vector<std::string>& ids_to_check,
653 const IdToComponentPtrMap& components,
654 const base::flat_map<std::string, std::string>& additional_attributes,
655 bool enabled_component_updates,
656 UpdateCheckCallback update_check_callback) override {
Sorin Jianu888ec292018-06-01 15:35:42657 /*
658 Mock the following response:
659
660 <?xml version='1.0' encoding='UTF-8'?>
661 <response protocol='3.1'>
662 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
663 <updatecheck status='ok'>
664 <urls>
665 <url codebase='http://localhost/download/'/>
666 </urls>
667 <manifest version='1.0' prodversionmin='11.0.1.0'>
668 <packages>
669 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:23670 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
671 a284a7cd8059c3409ce0498'/>
Sorin Jianu888ec292018-06-01 15:35:42672 </packages>
673 </manifest>
674 </updatecheck>
675 </app>
676 </response>
677 */
678 EXPECT_FALSE(session_id.empty());
679 EXPECT_TRUE(enabled_component_updates);
680 EXPECT_EQ(2u, ids_to_check.size());
681
682 ProtocolParser::Results results;
683 {
684 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
685 EXPECT_EQ(id, ids_to_check[0]);
686 EXPECT_EQ(1u, components.count(id));
687
688 ProtocolParser::Result::Manifest::Package package;
689 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
690 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:23691 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
Sorin Jianu888ec292018-06-01 15:35:42692
693 ProtocolParser::Result result;
694 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
695 result.status = "ok";
696 result.crx_urls.push_back(GURL("http://localhost/download/"));
697 result.manifest.version = "1.0";
698 result.manifest.browser_min_version = "11.0.1.0";
699 result.manifest.packages.push_back(package);
700 results.list.push_back(result);
701
702 EXPECT_FALSE(components.at(id)->is_foreground());
703 }
704
705 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46706 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
707 ErrorCategory::kNone, 0, 0));
Sorin Jianu888ec292018-06-01 15:35:42708 }
709 };
710
711 class MockCrxDownloader : public CrxDownloader {
712 public:
713 static std::unique_ptr<CrxDownloader> Create(
714 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:12715 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianu888ec292018-06-01 15:35:42716 return std::make_unique<MockCrxDownloader>();
717 }
718
719 MockCrxDownloader() : CrxDownloader(nullptr) {}
720
721 private:
722 void DoStartDownload(const GURL& url) override {
723 DownloadMetrics download_metrics;
724 download_metrics.url = url;
725 download_metrics.downloader = DownloadMetrics::kNone;
726 download_metrics.error = 0;
727 download_metrics.downloaded_bytes = 1843;
728 download_metrics.total_bytes = 1843;
729 download_metrics.download_time_ms = 1000;
730
731 FilePath path;
732 EXPECT_TRUE(MakeTestFile(
733 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
734
735 Result result;
736 result.error = 0;
737 result.response = path;
Sorin Jianu888ec292018-06-01 15:35:42738
739 base::ThreadTaskRunnerHandle::Get()->PostTask(
740 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:03741 base::Unretained(this)));
Sorin Jianu888ec292018-06-01 15:35:42742
743 base::ThreadTaskRunnerHandle::Get()->PostTask(
744 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
745 base::Unretained(this), true, result,
746 download_metrics));
747 }
748 };
749
750 class MockPingManager : public MockPingManagerImpl {
751 public:
752 explicit MockPingManager(scoped_refptr<Configurator> config)
753 : MockPingManagerImpl(config) {}
754
755 protected:
756 ~MockPingManager() override {
757 const auto ping_data = MockPingManagerImpl::ping_data();
758 EXPECT_EQ(1u, ping_data.size());
759 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
760 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
761 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
762 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
763 EXPECT_EQ(0, ping_data[0].error_code);
764 }
765 };
766
767 scoped_refptr<UpdateClient> update_client =
768 base::MakeRefCounted<UpdateClientImpl>(
769 config(), base::MakeRefCounted<MockPingManager>(config()),
770 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
771
772 MockObserver observer;
773 {
774 InSequence seq;
775 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
776 "jebgalgnebhfojomionfpkfelancnnkf"))
777 .Times(1);
778 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
779 "jebgalgnebhfojomionfpkfelancnnkf"))
780 .Times(1);
781 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
782 "jebgalgnebhfojomionfpkfelancnnkf"))
783 .Times(AtLeast(1));
784 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
785 "jebgalgnebhfojomionfpkfelancnnkf"))
786 .Times(1);
787 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
788 "jebgalgnebhfojomionfpkfelancnnkf"))
789 .Times(1);
790 }
791 {
792 InSequence seq;
793 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
794 "abagagagagagagagagagagagagagagag"))
795 .Times(1);
796 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
797 "abagagagagagagagagagagagagagagag"))
798 .Times(1)
799 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
800 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:53801 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianu888ec292018-06-01 15:35:42802 EXPECT_EQ(ComponentState::kUpdateError, item.state);
803 EXPECT_EQ(5, static_cast<int>(item.error_category));
804 EXPECT_EQ(-10004, item.error_code);
805 EXPECT_EQ(0, item.extra_code1);
806 }));
807 }
808
Sorin Jianudfb12a42020-03-10 04:12:03809 std::vector<CrxUpdateItem> items;
810 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
811 EXPECT_CALL(*receiver, Receive(_))
812 .WillRepeatedly(
813 [&items](const CrxUpdateItem& item) { items.push_back(item); });
Sorin Jianu888ec292018-06-01 15:35:42814
Sorin Jianudfb12a42020-03-10 04:12:03815 update_client->AddObserver(&observer);
Sorin Jianu888ec292018-06-01 15:35:42816 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
817 "abagagagagagagagagagagagagagagag"};
818 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:03819 ids, base::BindOnce(&DataCallbackMock::Callback),
820 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
821 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
Sorin Jianu888ec292018-06-01 15:35:42822 RunThreads();
823
Sorin Jianudfb12a42020-03-10 04:12:03824 EXPECT_EQ(8u, items.size());
825 EXPECT_EQ(ComponentState::kChecking, items[0].state);
826 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
827 EXPECT_EQ(ComponentState::kChecking, items[1].state);
828 EXPECT_STREQ("abagagagagagagagagagagagagagagag", items[1].id.c_str());
829 EXPECT_EQ(ComponentState::kCanUpdate, items[2].state);
830 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
831 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
832 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
833 EXPECT_EQ(ComponentState::kDownloading, items[4].state);
834 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
835 EXPECT_EQ(ComponentState::kUpdating, items[5].state);
836 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
837 EXPECT_EQ(ComponentState::kUpdated, items[6].state);
838 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[6].id.c_str());
839 EXPECT_EQ(ComponentState::kUpdateError, items[7].state);
840 EXPECT_STREQ("abagagagagagagagagagagagagagagag", items[7].id.c_str());
841
Sorin Jianu888ec292018-06-01 15:35:42842 update_client->RemoveObserver(&observer);
843}
844
Sorin Jianucb4431a2018-04-30 20:59:24845// Tests the update check for two CRXs scenario when the second CRX does not
846// provide a CrxComponent instance. In this case, the update is handled as
847// if only one component were provided as an argument to the |Update| call
848// with the exception that the second component still fires an event such as
849// |COMPONENT_UPDATE_ERROR|.
850TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentData) {
Sorin Jianua8926bf2018-03-09 21:02:53851 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:03852 public:
Sorin Jianu73900242018-08-17 01:11:53853 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:52854 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:53855 CrxComponent crx;
856 crx.name = "test_jebg";
857 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
858 crx.version = base::Version("0.9");
859 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:23860 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:53861 return {crx, base::nullopt};
sorin9797aba2015-04-17 17:15:03862 }
863 };
864
Sorin Jianua8926bf2018-03-09 21:02:53865 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:03866 public:
Sorin Jianua8ef73d2017-11-02 16:55:17867 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:41868 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:17869 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:03870 }
871 };
872
Sorin Jianua8926bf2018-03-09 21:02:53873 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:03874 public:
dchengd0fc6aa92016-04-22 18:03:12875 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:42876 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:49877 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:53878 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:03879 }
880
Sorin Jianuc303bf42018-09-07 16:19:33881 void CheckForUpdates(
882 const std::string& session_id,
883 const std::vector<std::string>& ids_to_check,
884 const IdToComponentPtrMap& components,
885 const base::flat_map<std::string, std::string>& additional_attributes,
886 bool enabled_component_updates,
887 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:03888 /*
Sorin Jianua8926bf2018-03-09 21:02:53889 Mock the following response:
sorin9797aba2015-04-17 17:15:03890
891 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:28892 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:03893 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
894 <updatecheck status='ok'>
895 <urls>
896 <url codebase='http://localhost/download/'/>
897 </urls>
898 <manifest version='1.0' prodversionmin='11.0.1.0'>
899 <packages>
sorin74e70672016-02-03 03:13:10900 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:23901 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
902 a284a7cd8059c3409ce0498'/>
sorin9797aba2015-04-17 17:15:03903 </packages>
904 </manifest>
905 </updatecheck>
906 </app>
sorin9797aba2015-04-17 17:15:03907 </response>
908 */
Sorin Jianud69d4372018-02-07 19:44:22909 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:48910 EXPECT_TRUE(enabled_component_updates);
Sorin Jianucb4431a2018-04-30 20:59:24911 EXPECT_EQ(1u, ids_to_check.size());
sorin9797aba2015-04-17 17:15:03912
Sorin Jianu888ec292018-06-01 15:35:42913 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:48914 {
915 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
916 EXPECT_EQ(id, ids_to_check[0]);
917 EXPECT_EQ(1u, components.count(id));
sorin9797aba2015-04-17 17:15:03918
sorin7cff6e52017-05-17 16:37:23919 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:48920 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
921 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:23922 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
sorin9797aba2015-04-17 17:15:03923
sorin7cff6e52017-05-17 16:37:23924 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:48925 result.extension_id = id;
926 result.status = "ok";
927 result.crx_urls.push_back(GURL("http://localhost/download/"));
928 result.manifest.version = "1.0";
929 result.manifest.browser_min_version = "11.0.1.0";
930 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:42931 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:03932
Sorin Jianu888ec292018-06-01 15:35:42933 EXPECT_FALSE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:48934 }
935
sorin9797aba2015-04-17 17:15:03936 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:46937 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
938 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:03939 }
940 };
941
Sorin Jianua8926bf2018-03-09 21:02:53942 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:03943 public:
dchengd0fc6aa92016-04-22 18:03:12944 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:03945 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:12946 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:53947 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:03948 }
949
Sorin Jianua8926bf2018-03-09 21:02:53950 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:03951
sorin30474f02017-04-27 00:45:48952 private:
sorin9797aba2015-04-17 17:15:03953 void DoStartDownload(const GURL& url) override {
954 DownloadMetrics download_metrics;
955 FilePath path;
956 Result result;
957 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
958 download_metrics.url = url;
959 download_metrics.downloader = DownloadMetrics::kNone;
960 download_metrics.error = 0;
961 download_metrics.downloaded_bytes = 1843;
962 download_metrics.total_bytes = 1843;
963 download_metrics.download_time_ms = 1000;
964
965 EXPECT_TRUE(MakeTestFile(
966 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
967
968 result.error = 0;
969 result.response = path;
sorin9797aba2015-04-17 17:15:03970 } else {
971 NOTREACHED();
972 }
973
974 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53975 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:03976 base::Unretained(this)));
sorin9797aba2015-04-17 17:15:03977
978 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:53979 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianua8ef73d2017-11-02 16:55:17980 base::Unretained(this), true, result,
981 download_metrics));
sorin9797aba2015-04-17 17:15:03982 }
983 };
984
Sorin Jianua8926bf2018-03-09 21:02:53985 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:03986 public:
Sorin Jianua8926bf2018-03-09 21:02:53987 explicit MockPingManager(scoped_refptr<Configurator> config)
988 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:54989
990 protected:
Sorin Jianua8926bf2018-03-09 21:02:53991 ~MockPingManager() override {
992 const auto ping_data = MockPingManagerImpl::ping_data();
Sorin Jianucb4431a2018-04-30 20:59:24993 EXPECT_EQ(1u, ping_data.size());
sorin30474f02017-04-27 00:45:48994 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
995 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
996 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:10997 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:48998 EXPECT_EQ(0, ping_data[0].error_code);
sorin9797aba2015-04-17 17:15:03999 }
1000 };
1001
sorin30474f02017-04-27 00:45:481002 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431003 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531004 config(), base::MakeRefCounted<MockPingManager>(config()),
1005 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031006
1007 MockObserver observer;
1008 {
1009 InSequence seq;
1010 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1011 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1012 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1013 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1014 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481015 "jebgalgnebhfojomionfpkfelancnnkf"))
1016 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031017 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1018 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1019 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1020 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1021 }
1022 {
1023 InSequence seq;
Sorin Jianucb4431a2018-04-30 20:59:241024 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorin30474f02017-04-27 00:45:481025 "ihfokbkgjpifnbbojhneepfflplebdkc"))
Sorin Jianucb4431a2018-04-30 20:59:241026 .Times(1);
1027 }
1028
Sorin Jianudfb12a42020-03-10 04:12:031029 std::vector<CrxUpdateItem> items;
1030 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
1031 EXPECT_CALL(*receiver, Receive(_))
1032 .WillRepeatedly(
1033 [&items](const CrxUpdateItem& item) { items.push_back(item); });
Sorin Jianucb4431a2018-04-30 20:59:241034
Sorin Jianudfb12a42020-03-10 04:12:031035 update_client->AddObserver(&observer);
Sorin Jianucb4431a2018-04-30 20:59:241036 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1037 "ihfokbkgjpifnbbojhneepfflplebdkc"};
1038 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:031039 ids, base::BindOnce(&DataCallbackMock::Callback),
1040 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
1041 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
Sorin Jianucb4431a2018-04-30 20:59:241042 RunThreads();
1043
Sorin Jianudfb12a42020-03-10 04:12:031044 EXPECT_EQ(7u, items.size());
1045 EXPECT_EQ(ComponentState::kChecking, items[0].state);
1046 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
1047 EXPECT_EQ(ComponentState::kUpdateError, items[1].state);
1048 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
1049 EXPECT_EQ(ComponentState::kCanUpdate, items[2].state);
1050 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
1051 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
1052 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
1053 EXPECT_EQ(ComponentState::kDownloading, items[4].state);
1054 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
1055 EXPECT_EQ(ComponentState::kUpdating, items[5].state);
1056 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
1057 EXPECT_EQ(ComponentState::kUpdated, items[6].state);
1058 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[6].id.c_str());
1059
Sorin Jianucb4431a2018-04-30 20:59:241060 update_client->RemoveObserver(&observer);
1061}
1062
1063// Tests the update check for two CRXs scenario when no CrxComponent data is
1064// provided for either component. In this case, no update check occurs, and
1065// |COMPONENT_UPDATE_ERROR| event fires for both components.
1066TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentDataAtAll) {
1067 class DataCallbackMock {
1068 public:
Sorin Jianu73900242018-08-17 01:11:531069 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianucb4431a2018-04-30 20:59:241070 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:531071 return {base::nullopt, base::nullopt};
Sorin Jianucb4431a2018-04-30 20:59:241072 }
1073 };
1074
1075 class CompletionCallbackMock {
1076 public:
1077 static void Callback(base::OnceClosure quit_closure, Error error) {
1078 EXPECT_EQ(Error::NONE, error);
1079 std::move(quit_closure).Run();
1080 }
1081 };
1082
1083 class MockUpdateChecker : public UpdateChecker {
1084 public:
1085 static std::unique_ptr<UpdateChecker> Create(
1086 scoped_refptr<Configurator> config,
1087 PersistedData* metadata) {
1088 return std::make_unique<MockUpdateChecker>();
1089 }
1090
Sorin Jianuc303bf42018-09-07 16:19:331091 void CheckForUpdates(
1092 const std::string& session_id,
1093 const std::vector<std::string>& ids_to_check,
1094 const IdToComponentPtrMap& components,
1095 const base::flat_map<std::string, std::string>& additional_attributes,
1096 bool enabled_component_updates,
1097 UpdateCheckCallback update_check_callback) override {
Sorin Jianucb4431a2018-04-30 20:59:241098 NOTREACHED();
1099 }
1100 };
1101
1102 class MockCrxDownloader : public CrxDownloader {
1103 public:
1104 static std::unique_ptr<CrxDownloader> Create(
1105 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:121106 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianucb4431a2018-04-30 20:59:241107 return std::make_unique<MockCrxDownloader>();
1108 }
1109
1110 MockCrxDownloader() : CrxDownloader(nullptr) {}
1111
1112 private:
1113 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
1114 };
1115
1116 class MockPingManager : public MockPingManagerImpl {
1117 public:
1118 explicit MockPingManager(scoped_refptr<Configurator> config)
1119 : MockPingManagerImpl(config) {}
1120
1121 protected:
1122 ~MockPingManager() override {
1123 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
1124 }
1125 };
1126
1127 scoped_refptr<UpdateClient> update_client =
1128 base::MakeRefCounted<UpdateClientImpl>(
1129 config(), base::MakeRefCounted<MockPingManager>(config()),
1130 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
1131
1132 MockObserver observer;
1133 {
1134 InSequence seq;
1135 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1136 "jebgalgnebhfojomionfpkfelancnnkf"))
1137 .Times(1);
1138 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1139 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1140 .Times(1);
sorin9797aba2015-04-17 17:15:031141 }
1142
Sorin Jianudfb12a42020-03-10 04:12:031143 std::vector<CrxUpdateItem> items;
1144 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
1145 EXPECT_CALL(*receiver, Receive(_))
1146 .WillRepeatedly(
1147 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin9797aba2015-04-17 17:15:031148
Sorin Jianudfb12a42020-03-10 04:12:031149 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:481150 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1151 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031152 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:031153 ids, base::BindOnce(&DataCallbackMock::Callback),
1154 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
1155 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:031156 RunThreads();
1157
Sorin Jianudfb12a42020-03-10 04:12:031158 EXPECT_EQ(2u, items.size());
1159 EXPECT_EQ(ComponentState::kUpdateError, items[0].state);
1160 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
1161 EXPECT_EQ(ComponentState::kUpdateError, items[1].state);
1162 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
1163
sorin9797aba2015-04-17 17:15:031164 update_client->RemoveObserver(&observer);
1165}
1166
sorin6bb8de42015-06-03 00:23:271167// Tests the scenario where there is a download timeout for the first
1168// CRX. The update for the first CRX fails. The update client waits before
1169// attempting the update for the second CRX. This update succeeds.
1170TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
Sorin Jianua8926bf2018-03-09 21:02:531171 class DataCallbackMock {
sorin6bb8de42015-06-03 00:23:271172 public:
Sorin Jianu73900242018-08-17 01:11:531173 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:521174 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:531175 CrxComponent crx1;
1176 crx1.name = "test_jebg";
1177 crx1.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
1178 crx1.version = base::Version("0.9");
1179 crx1.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:231180 crx1.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin6bb8de42015-06-03 00:23:271181
Sorin Jianu73900242018-08-17 01:11:531182 CrxComponent crx2;
1183 crx2.name = "test_ihfo";
1184 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
1185 crx2.version = base::Version("0.8");
1186 crx2.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:231187 crx2.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin6bb8de42015-06-03 00:23:271188
Sorin Jianu73900242018-08-17 01:11:531189 return {crx1, crx2};
sorin6bb8de42015-06-03 00:23:271190 }
1191 };
1192
Sorin Jianua8926bf2018-03-09 21:02:531193 class CompletionCallbackMock {
sorin6bb8de42015-06-03 00:23:271194 public:
Sorin Jianua8ef73d2017-11-02 16:55:171195 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411196 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171197 std::move(quit_closure).Run();
sorin6bb8de42015-06-03 00:23:271198 }
1199 };
1200
Sorin Jianua8926bf2018-03-09 21:02:531201 class MockUpdateChecker : public UpdateChecker {
sorin6bb8de42015-06-03 00:23:271202 public:
dchengd0fc6aa92016-04-22 18:03:121203 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421204 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491205 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531206 return std::make_unique<MockUpdateChecker>();
sorin6bb8de42015-06-03 00:23:271207 }
1208
Sorin Jianuc303bf42018-09-07 16:19:331209 void CheckForUpdates(
1210 const std::string& session_id,
1211 const std::vector<std::string>& ids_to_check,
1212 const IdToComponentPtrMap& components,
1213 const base::flat_map<std::string, std::string>& additional_attributes,
1214 bool enabled_component_updates,
1215 UpdateCheckCallback update_check_callback) override {
sorin6bb8de42015-06-03 00:23:271216 /*
Sorin Jianua8926bf2018-03-09 21:02:531217 Mock the following response:
sorin6bb8de42015-06-03 00:23:271218
1219 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281220 <response protocol='3.1'>
sorin6bb8de42015-06-03 00:23:271221 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1222 <updatecheck status='ok'>
1223 <urls>
1224 <url codebase='http://localhost/download/'/>
1225 </urls>
1226 <manifest version='1.0' prodversionmin='11.0.1.0'>
1227 <packages>
sorin74e70672016-02-03 03:13:101228 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:231229 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
1230 a284a7cd8059c3409ce0498'/>
sorin6bb8de42015-06-03 00:23:271231 </packages>
1232 </manifest>
1233 </updatecheck>
1234 </app>
1235 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1236 <updatecheck status='ok'>
1237 <urls>
1238 <url codebase='http://localhost/download/'/>
1239 </urls>
1240 <manifest version='1.0' prodversionmin='11.0.1.0'>
1241 <packages>
sorin74e70672016-02-03 03:13:101242 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:231243 hash_sha256='8f5aa190311237cae00675af87ff457f278cd1a05
1244 895470ac5d46647d4a3c2ea'/>
sorin6bb8de42015-06-03 00:23:271245 </packages>
1246 </manifest>
1247 </updatecheck>
1248 </app>
1249 </response>
1250 */
sorin6bb8de42015-06-03 00:23:271251
Sorin Jianud69d4372018-02-07 19:44:221252 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:481253 EXPECT_TRUE(enabled_component_updates);
1254 EXPECT_EQ(2u, ids_to_check.size());
sorin6bb8de42015-06-03 00:23:271255
Sorin Jianu888ec292018-06-01 15:35:421256 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:481257 {
1258 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
1259 EXPECT_EQ(id, ids_to_check[0]);
1260 EXPECT_EQ(1u, components.count(id));
sorin6bb8de42015-06-03 00:23:271261
sorin7cff6e52017-05-17 16:37:231262 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:481263 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
1264 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231265 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
sorin6bb8de42015-06-03 00:23:271266
sorin7cff6e52017-05-17 16:37:231267 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481268 result.extension_id = id;
1269 result.status = "ok";
1270 result.crx_urls.push_back(GURL("http://localhost/download/"));
1271 result.manifest.version = "1.0";
1272 result.manifest.browser_min_version = "11.0.1.0";
1273 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421274 results.list.push_back(result);
sorin30474f02017-04-27 00:45:481275 }
1276
1277 {
1278 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1279 EXPECT_EQ(id, ids_to_check[1]);
1280 EXPECT_EQ(1u, components.count(id));
1281
sorin7cff6e52017-05-17 16:37:231282 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:481283 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
1284 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231285 "8f5aa190311237cae00675af87ff457f278cd1a05895470ac5d46647d4a3c2ea";
sorin30474f02017-04-27 00:45:481286
sorin7cff6e52017-05-17 16:37:231287 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481288 result.extension_id = id;
1289 result.status = "ok";
1290 result.crx_urls.push_back(GURL("http://localhost/download/"));
1291 result.manifest.version = "1.0";
1292 result.manifest.browser_min_version = "11.0.1.0";
1293 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421294 results.list.push_back(result);
sorin30474f02017-04-27 00:45:481295 }
sorin6bb8de42015-06-03 00:23:271296
1297 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461298 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1299 ErrorCategory::kNone, 0, 0));
sorin6bb8de42015-06-03 00:23:271300 }
1301 };
1302
Sorin Jianua8926bf2018-03-09 21:02:531303 class MockCrxDownloader : public CrxDownloader {
sorin6bb8de42015-06-03 00:23:271304 public:
dchengd0fc6aa92016-04-22 18:03:121305 static std::unique_ptr<CrxDownloader> Create(
sorin6bb8de42015-06-03 00:23:271306 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:121307 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:531308 return std::make_unique<MockCrxDownloader>();
sorin6bb8de42015-06-03 00:23:271309 }
1310
Sorin Jianua8926bf2018-03-09 21:02:531311 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin6bb8de42015-06-03 00:23:271312
sorin30474f02017-04-27 00:45:481313 private:
sorin6bb8de42015-06-03 00:23:271314 void DoStartDownload(const GURL& url) override {
1315 DownloadMetrics download_metrics;
1316 FilePath path;
1317 Result result;
1318 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
1319 download_metrics.url = url;
1320 download_metrics.downloader = DownloadMetrics::kNone;
1321 download_metrics.error = -118;
1322 download_metrics.downloaded_bytes = 0;
1323 download_metrics.total_bytes = 0;
1324 download_metrics.download_time_ms = 1000;
1325
Sorin Jianu52de5fa2017-10-09 23:19:331326 // The result must not include a file path in the case of errors.
sorin6bb8de42015-06-03 00:23:271327 result.error = -118;
sorin6bb8de42015-06-03 00:23:271328 } else if (url.path() ==
1329 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1330 download_metrics.url = url;
1331 download_metrics.downloader = DownloadMetrics::kNone;
1332 download_metrics.error = 0;
1333 download_metrics.downloaded_bytes = 53638;
1334 download_metrics.total_bytes = 53638;
1335 download_metrics.download_time_ms = 2000;
1336
1337 EXPECT_TRUE(MakeTestFile(
1338 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1339
1340 result.error = 0;
1341 result.response = path;
sorin6bb8de42015-06-03 00:23:271342 } else {
1343 NOTREACHED();
1344 }
1345
1346 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531347 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:031348 base::Unretained(this)));
sorin6bb8de42015-06-03 00:23:271349
1350 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531351 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581352 base::Unretained(this), true, result,
1353 download_metrics));
sorin6bb8de42015-06-03 00:23:271354 }
1355 };
1356
Sorin Jianua8926bf2018-03-09 21:02:531357 class MockPingManager : public MockPingManagerImpl {
sorin6bb8de42015-06-03 00:23:271358 public:
Sorin Jianua8926bf2018-03-09 21:02:531359 explicit MockPingManager(scoped_refptr<Configurator> config)
1360 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541361
1362 protected:
Sorin Jianua8926bf2018-03-09 21:02:531363 ~MockPingManager() override {
1364 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481365 EXPECT_EQ(2u, ping_data.size());
1366 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1367 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1368 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101369 EXPECT_EQ(1, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:481370 EXPECT_EQ(-118, ping_data[0].error_code);
1371 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1372 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
1373 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101374 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:481375 EXPECT_EQ(0, ping_data[1].error_code);
sorin6bb8de42015-06-03 00:23:271376 }
1377 };
1378
sorin30474f02017-04-27 00:45:481379 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431380 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531381 config(), base::MakeRefCounted<MockPingManager>(config()),
1382 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin6bb8de42015-06-03 00:23:271383
1384 MockObserver observer;
1385 {
1386 InSequence seq;
1387 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1388 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1389 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1390 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
1391 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481392 "jebgalgnebhfojomionfpkfelancnnkf"))
1393 .Times(AtLeast(1));
Sorin Jianucbb10e12018-01-23 18:01:441394 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
1395 "jebgalgnebhfojomionfpkfelancnnkf"))
Sorin Jianuafcb70dd2018-05-16 20:14:151396 .Times(1)
1397 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
1398 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:531399 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianuafcb70dd2018-05-16 20:14:151400 EXPECT_EQ(ComponentState::kUpdateError, item.state);
Minh X. Nguyena4640cb2018-05-23 21:29:101401 EXPECT_EQ(1, static_cast<int>(item.error_category));
Sorin Jianuafcb70dd2018-05-16 20:14:151402 EXPECT_EQ(-118, item.error_code);
1403 EXPECT_EQ(0, item.extra_code1);
1404 }));
sorin6bb8de42015-06-03 00:23:271405 }
1406 {
1407 InSequence seq;
1408 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1409 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1410 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1411 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1412 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
1413 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1414 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481415 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1416 .Times(AtLeast(1));
sorin6bb8de42015-06-03 00:23:271417 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1418 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1419 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1420 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1421 }
1422
Sorin Jianudfb12a42020-03-10 04:12:031423 std::vector<CrxUpdateItem> items;
1424 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
1425 EXPECT_CALL(*receiver, Receive(_))
1426 .WillRepeatedly(
1427 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin6bb8de42015-06-03 00:23:271428
Sorin Jianudfb12a42020-03-10 04:12:031429 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:481430 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
1431 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin6bb8de42015-06-03 00:23:271432 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:031433 ids, base::BindOnce(&DataCallbackMock::Callback),
1434 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
1435 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin6bb8de42015-06-03 00:23:271436 RunThreads();
1437
Sorin Jianudfb12a42020-03-10 04:12:031438 EXPECT_EQ(11u, items.size());
1439 EXPECT_EQ(ComponentState::kChecking, items[0].state);
1440 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
1441 EXPECT_EQ(ComponentState::kChecking, items[1].state);
1442 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
1443 EXPECT_EQ(ComponentState::kCanUpdate, items[2].state);
1444 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
1445 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
1446 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
1447 EXPECT_EQ(ComponentState::kDownloading, items[4].state);
1448 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
1449 EXPECT_EQ(ComponentState::kUpdateError, items[5].state);
1450 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
1451 EXPECT_EQ(ComponentState::kCanUpdate, items[6].state);
1452 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[6].id.c_str());
1453 EXPECT_EQ(ComponentState::kDownloading, items[7].state);
1454 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[7].id.c_str());
1455 EXPECT_EQ(ComponentState::kDownloading, items[8].state);
1456 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[8].id.c_str());
1457 EXPECT_EQ(ComponentState::kUpdating, items[9].state);
1458 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[9].id.c_str());
1459 EXPECT_EQ(ComponentState::kUpdated, items[10].state);
1460 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[10].id.c_str());
1461
sorin6bb8de42015-06-03 00:23:271462 update_client->RemoveObserver(&observer);
sorin6bb8de42015-06-03 00:23:271463}
1464
sorin9797aba2015-04-17 17:15:031465// Tests the differential update scenario for one CRX.
1466TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:531467 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031468 public:
Sorin Jianu73900242018-08-17 01:11:531469 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:521470 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:031471 static int num_calls = 0;
1472
1473 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:481474 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431475 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:031476
1477 ++num_calls;
1478
Sorin Jianu73900242018-08-17 01:11:531479 CrxComponent crx;
1480 crx.name = "test_ihfo";
1481 crx.pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
1482 crx.installer = installer;
Joshua Pawlickiafaa2922019-09-03 18:50:231483 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin9797aba2015-04-17 17:15:031484 if (num_calls == 1) {
Sorin Jianu73900242018-08-17 01:11:531485 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:031486 } else if (num_calls == 2) {
Sorin Jianu73900242018-08-17 01:11:531487 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:031488 } else {
1489 NOTREACHED();
1490 }
1491
Sorin Jianu73900242018-08-17 01:11:531492 return {crx};
sorin9797aba2015-04-17 17:15:031493 }
1494 };
1495
Sorin Jianua8926bf2018-03-09 21:02:531496 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031497 public:
Sorin Jianua8ef73d2017-11-02 16:55:171498 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411499 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171500 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031501 }
1502 };
1503
Sorin Jianua8926bf2018-03-09 21:02:531504 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031505 public:
dchengd0fc6aa92016-04-22 18:03:121506 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421507 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491508 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531509 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031510 }
1511
Sorin Jianuc303bf42018-09-07 16:19:331512 void CheckForUpdates(
1513 const std::string& session_id,
1514 const std::vector<std::string>& ids_to_check,
1515 const IdToComponentPtrMap& components,
1516 const base::flat_map<std::string, std::string>& additional_attributes,
1517 bool enabled_component_updates,
1518 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:221519 EXPECT_FALSE(session_id.empty());
1520
sorin9797aba2015-04-17 17:15:031521 static int num_call = 0;
1522 ++num_call;
1523
sorin7cff6e52017-05-17 16:37:231524 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:031525
1526 if (num_call == 1) {
1527 /*
Sorin Jianua8926bf2018-03-09 21:02:531528 Mock the following response:
sorin9797aba2015-04-17 17:15:031529 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281530 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031531 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1532 <updatecheck status='ok'>
1533 <urls>
1534 <url codebase='http://localhost/download/'/>
1535 </urls>
1536 <manifest version='1.0' prodversionmin='11.0.1.0'>
1537 <packages>
sorin74e70672016-02-03 03:13:101538 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
1539 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
1540 3f309f156ea6d27229c0b3f9'/>
sorin9797aba2015-04-17 17:15:031541 </packages>
1542 </manifest>
1543 </updatecheck>
1544 </app>
1545 </response>
1546 */
sorin30474f02017-04-27 00:45:481547 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1548 EXPECT_EQ(id, ids_to_check[0]);
1549 EXPECT_EQ(1u, components.count(id));
1550
sorin7cff6e52017-05-17 16:37:231551 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031552 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:101553 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231554 "8f5aa190311237cae00675af87ff457f278cd1a05895470ac5d46647d4a3c2ea";
sorin30474f02017-04-27 00:45:481555
sorin7cff6e52017-05-17 16:37:231556 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481557 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171558 result.status = "ok";
sorin9797aba2015-04-17 17:15:031559 result.crx_urls.push_back(GURL("http://localhost/download/"));
1560 result.manifest.version = "1.0";
1561 result.manifest.browser_min_version = "11.0.1.0";
1562 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421563 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031564 } else if (num_call == 2) {
1565 /*
Sorin Jianua8926bf2018-03-09 21:02:531566 Mock the following response:
sorin9797aba2015-04-17 17:15:031567 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281568 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031569 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
1570 <updatecheck status='ok'>
1571 <urls>
1572 <url codebase='http://localhost/download/'/>
1573 <url codebasediff='http://localhost/download/'/>
1574 </urls>
1575 <manifest version='2.0' prodversionmin='11.0.1.0'>
1576 <packages>
1577 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
1578 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:231579 hash_sha256='c87d8742c3ff3d7a0cb6f3c91aa2fcf3dea6361
1580 8086a7db1c5be5300e1d4d6b6'
sorin74e70672016-02-03 03:13:101581 fp='22'
Joshua Pawlickiafaa2922019-09-03 18:50:231582 hashdiff_sha256='0fd48a5dd87006a709756cfc47198cbc4c4
1583 928f33ac4277d79573c15164a33eb'/>
sorin9797aba2015-04-17 17:15:031584 </packages>
1585 </manifest>
1586 </updatecheck>
1587 </app>
1588 </response>
1589 */
sorin30474f02017-04-27 00:45:481590 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
1591 EXPECT_EQ(id, ids_to_check[0]);
1592 EXPECT_EQ(1u, components.count(id));
1593
sorin7cff6e52017-05-17 16:37:231594 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031595 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
1596 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:101597 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231598 "c87d8742c3ff3d7a0cb6f3c91aa2fcf3dea63618086a7db1c5be5300e1d4d6b6";
sorin74e70672016-02-03 03:13:101599 package.hashdiff_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231600 "0fd48a5dd87006a709756cfc47198cbc4c4928f33ac4277d79573c15164a33eb";
sorin9797aba2015-04-17 17:15:031601 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:481602
sorin7cff6e52017-05-17 16:37:231603 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481604 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171605 result.status = "ok";
sorin9797aba2015-04-17 17:15:031606 result.crx_urls.push_back(GURL("http://localhost/download/"));
1607 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
1608 result.manifest.version = "2.0";
1609 result.manifest.browser_min_version = "11.0.1.0";
1610 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:421611 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031612 } else {
1613 NOTREACHED();
1614 }
1615
1616 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461617 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1618 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:031619 }
1620 };
1621
Sorin Jianua8926bf2018-03-09 21:02:531622 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031623 public:
dchengd0fc6aa92016-04-22 18:03:121624 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031625 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:121626 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:531627 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031628 }
1629
Sorin Jianua8926bf2018-03-09 21:02:531630 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031631
sorin30474f02017-04-27 00:45:481632 private:
sorin9797aba2015-04-17 17:15:031633 void DoStartDownload(const GURL& url) override {
1634 DownloadMetrics download_metrics;
1635 FilePath path;
1636 Result result;
1637 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
1638 download_metrics.url = url;
1639 download_metrics.downloader = DownloadMetrics::kNone;
1640 download_metrics.error = 0;
1641 download_metrics.downloaded_bytes = 53638;
1642 download_metrics.total_bytes = 53638;
1643 download_metrics.download_time_ms = 2000;
1644
1645 EXPECT_TRUE(MakeTestFile(
1646 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
1647
1648 result.error = 0;
1649 result.response = path;
sorin9797aba2015-04-17 17:15:031650 } else if (url.path() ==
1651 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
1652 download_metrics.url = url;
1653 download_metrics.downloader = DownloadMetrics::kNone;
1654 download_metrics.error = 0;
1655 download_metrics.downloaded_bytes = 2105;
1656 download_metrics.total_bytes = 2105;
1657 download_metrics.download_time_ms = 1000;
1658
1659 EXPECT_TRUE(MakeTestFile(
1660 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
1661
1662 result.error = 0;
1663 result.response = path;
sorin9797aba2015-04-17 17:15:031664 } else {
1665 NOTREACHED();
1666 }
1667
1668 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531669 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:031670 base::Unretained(this)));
sorin9797aba2015-04-17 17:15:031671
1672 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531673 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581674 base::Unretained(this), true, result,
1675 download_metrics));
sorin9797aba2015-04-17 17:15:031676 }
1677 };
1678
Sorin Jianua8926bf2018-03-09 21:02:531679 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031680 public:
Sorin Jianua8926bf2018-03-09 21:02:531681 explicit MockPingManager(scoped_refptr<Configurator> config)
1682 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541683
1684 protected:
Sorin Jianua8926bf2018-03-09 21:02:531685 ~MockPingManager() override {
1686 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481687 EXPECT_EQ(2u, ping_data.size());
1688 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
1689 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
1690 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101691 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:481692 EXPECT_EQ(0, ping_data[0].error_code);
1693 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
1694 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
1695 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
1696 EXPECT_FALSE(ping_data[1].diff_update_failed);
Minh X. Nguyena4640cb2018-05-23 21:29:101697 EXPECT_EQ(0, static_cast<int>(ping_data[1].diff_error_category));
sorin30474f02017-04-27 00:45:481698 EXPECT_EQ(0, ping_data[1].diff_error_code);
Minh X. Nguyena4640cb2018-05-23 21:29:101699 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:481700 EXPECT_EQ(0, ping_data[1].error_code);
sorin9797aba2015-04-17 17:15:031701 }
1702 };
1703
sorin30474f02017-04-27 00:45:481704 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431705 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531706 config(), base::MakeRefCounted<MockPingManager>(config()),
1707 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:031708
1709 MockObserver observer;
1710 {
1711 InSequence seq;
1712 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1713 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1714 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1715 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1716 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481717 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1718 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031719 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1720 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1721 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1722 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1723 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
1724 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1725 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
1726 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1727 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:481728 "ihfokbkgjpifnbbojhneepfflplebdkc"))
1729 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:031730 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
1731 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1732 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
1733 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
1734 }
1735
1736 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:481737 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:031738 {
Sorin Jianudfb12a42020-03-10 04:12:031739 std::vector<CrxUpdateItem> items;
1740 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
1741 EXPECT_CALL(*receiver, Receive(_))
1742 .WillRepeatedly(
1743 [&items](const CrxUpdateItem& item) { items.push_back(item); });
1744
sorin9797aba2015-04-17 17:15:031745 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:031746 update_client->Update(
1747 ids, base::BindOnce(&DataCallbackMock::Callback),
1748 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
1749 false,
1750 base::BindOnce(&CompletionCallbackMock::Callback,
1751 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031752 runloop.Run();
Sorin Jianudfb12a42020-03-10 04:12:031753
1754 EXPECT_EQ(6u, items.size());
1755 EXPECT_EQ(ComponentState::kChecking, items[0].state);
1756 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[0].id.c_str());
1757 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
1758 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
1759 EXPECT_EQ(ComponentState::kDownloading, items[2].state);
1760 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[2].id.c_str());
1761 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
1762 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[3].id.c_str());
1763 EXPECT_EQ(ComponentState::kUpdating, items[4].state);
1764 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[4].id.c_str());
1765 EXPECT_EQ(ComponentState::kUpdated, items[5].state);
1766 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[5].id.c_str());
sorin9797aba2015-04-17 17:15:031767 }
1768
1769 {
Sorin Jianudfb12a42020-03-10 04:12:031770 std::vector<CrxUpdateItem> items;
1771 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
1772 EXPECT_CALL(*receiver, Receive(_))
1773 .WillRepeatedly(
1774 [&items](const CrxUpdateItem& item) { items.push_back(item); });
1775
sorin9797aba2015-04-17 17:15:031776 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:031777 update_client->Update(
1778 ids, base::BindOnce(&DataCallbackMock::Callback),
1779 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
1780 false,
1781 base::BindOnce(&CompletionCallbackMock::Callback,
1782 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:031783 runloop.Run();
Sorin Jianudfb12a42020-03-10 04:12:031784
1785 EXPECT_EQ(6u, items.size());
1786 EXPECT_EQ(ComponentState::kChecking, items[0].state);
1787 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[0].id.c_str());
1788 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
1789 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
1790 EXPECT_EQ(ComponentState::kDownloadingDiff, items[2].state);
1791 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[2].id.c_str());
1792 EXPECT_EQ(ComponentState::kDownloadingDiff, items[3].state);
1793 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[3].id.c_str());
1794 EXPECT_EQ(ComponentState::kUpdatingDiff, items[4].state);
1795 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[4].id.c_str());
1796 EXPECT_EQ(ComponentState::kUpdated, items[5].state);
1797 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[5].id.c_str());
sorin9797aba2015-04-17 17:15:031798 }
1799
1800 update_client->RemoveObserver(&observer);
1801}
1802
1803// Tests the update scenario for one CRX where the CRX installer returns
Sorin Jianuf40ab4b32017-10-06 22:53:411804// an error. Tests that the |unpack_path| argument refers to a valid path
1805// then |Install| is called, then tests that the |unpack| path is deleted
1806// by the |update_client| code before the test ends.
sorin9797aba2015-04-17 17:15:031807TEST_F(UpdateClientTest, OneCrxInstallError) {
1808 class MockInstaller : public CrxInstaller {
1809 public:
1810 MOCK_METHOD1(OnUpdateError, void(int error));
Sorin Jianua8ef73d2017-11-02 16:55:171811 MOCK_METHOD2(DoInstall,
Sorin Jianu7aa6d1f2017-10-13 20:29:291812 void(const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:411813 const Callback& callback));
sorin9797aba2015-04-17 17:15:031814 MOCK_METHOD2(GetInstalledFile,
1815 bool(const std::string& file, base::FilePath* installed_file));
1816 MOCK_METHOD0(Uninstall, bool());
1817
Sorin Jianua8ef73d2017-11-02 16:55:171818 void Install(const base::FilePath& unpack_path,
1819 const std::string& public_key,
Sorin Jianu9d64af672020-02-05 19:14:341820 std::unique_ptr<InstallParams> /*install_params*/,
Daniel Cheng67848522018-04-27 22:04:411821 Callback callback) override {
Sorin Jianua8ef73d2017-11-02 16:55:171822 DoInstall(unpack_path, std::move(callback));
1823
Sorin Jianu23f70f752017-05-30 16:21:581824 unpack_path_ = unpack_path;
1825 EXPECT_TRUE(base::DirectoryExists(unpack_path_));
Gabriel Charettedd8d5985e2020-02-26 18:38:351826 base::ThreadPool::PostTask(
1827 FROM_HERE, {base::MayBlock()},
Sorin Jianua8ef73d2017-11-02 16:55:171828 base::BindOnce(std::move(callback),
Sorin Jianuf40ab4b32017-10-06 22:53:411829 CrxInstaller::Result(InstallError::GENERIC_ERROR)));
sorin9797aba2015-04-17 17:15:031830 }
1831
1832 protected:
Sorin Jianu23f70f752017-05-30 16:21:581833 ~MockInstaller() override {
1834 // The unpack path is deleted unconditionally by the component state code,
1835 // which is driving this installer. Therefore, the unpack path must not
1836 // exist when this object is destroyed.
1837 if (!unpack_path_.empty())
1838 EXPECT_FALSE(base::DirectoryExists(unpack_path_));
1839 }
1840
1841 private:
1842 // Contains the |unpack_path| argument of the Install call.
1843 base::FilePath unpack_path_;
sorin9797aba2015-04-17 17:15:031844 };
1845
Sorin Jianua8926bf2018-03-09 21:02:531846 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:031847 public:
Sorin Jianu73900242018-08-17 01:11:531848 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:521849 const std::vector<std::string>& ids) {
sorin30474f02017-04-27 00:45:481850 scoped_refptr<MockInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:431851 base::MakeRefCounted<MockInstaller>();
sorin9797aba2015-04-17 17:15:031852
1853 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
Sorin Jianua8ef73d2017-11-02 16:55:171854 EXPECT_CALL(*installer, DoInstall(_, _)).Times(1);
sorin9797aba2015-04-17 17:15:031855 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
1856 EXPECT_CALL(*installer, Uninstall()).Times(0);
1857
Sorin Jianu73900242018-08-17 01:11:531858 CrxComponent crx;
1859 crx.name = "test_jebg";
1860 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
1861 crx.version = base::Version("0.9");
1862 crx.installer = installer;
Joshua Pawlickiafaa2922019-09-03 18:50:231863 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu7c22795b2018-04-26 22:16:521864
Sorin Jianu73900242018-08-17 01:11:531865 return {crx};
sorin9797aba2015-04-17 17:15:031866 }
1867 };
1868
Sorin Jianua8926bf2018-03-09 21:02:531869 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:031870 public:
Sorin Jianua8ef73d2017-11-02 16:55:171871 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:411872 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:171873 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:031874 }
1875 };
1876
Sorin Jianua8926bf2018-03-09 21:02:531877 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:031878 public:
dchengd0fc6aa92016-04-22 18:03:121879 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:421880 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:491881 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:531882 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:031883 }
1884
Sorin Jianuc303bf42018-09-07 16:19:331885 void CheckForUpdates(
1886 const std::string& session_id,
1887 const std::vector<std::string>& ids_to_check,
1888 const IdToComponentPtrMap& components,
1889 const base::flat_map<std::string, std::string>& additional_attributes,
1890 bool enabled_component_updates,
1891 UpdateCheckCallback update_check_callback) override {
sorin9797aba2015-04-17 17:15:031892 /*
Sorin Jianua8926bf2018-03-09 21:02:531893 Mock the following response:
sorin9797aba2015-04-17 17:15:031894
1895 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:281896 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:031897 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
1898 <updatecheck status='ok'>
1899 <urls>
1900 <url codebase='http://localhost/download/'/>
1901 </urls>
1902 <manifest version='1.0' prodversionmin='11.0.1.0'>
1903 <packages>
sorin74e70672016-02-03 03:13:101904 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:231905 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
1906 a284a7cd8059c3409ce0498'/>
sorin9797aba2015-04-17 17:15:031907 </packages>
1908 </manifest>
1909 </updatecheck>
1910 </app>
1911 </response>
1912 */
Sorin Jianud69d4372018-02-07 19:44:221913 EXPECT_FALSE(session_id.empty());
1914
sorin30474f02017-04-27 00:45:481915 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
1916 EXPECT_EQ(id, ids_to_check[0]);
1917 EXPECT_EQ(1u, components.count(id));
1918
sorin7cff6e52017-05-17 16:37:231919 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:031920 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:101921 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:231922 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
sorin30474f02017-04-27 00:45:481923
sorin7cff6e52017-05-17 16:37:231924 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:481925 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:171926 result.status = "ok";
sorin9797aba2015-04-17 17:15:031927 result.crx_urls.push_back(GURL("http://localhost/download/"));
1928 result.manifest.version = "1.0";
1929 result.manifest.browser_min_version = "11.0.1.0";
1930 result.manifest.packages.push_back(package);
1931
Sorin Jianu888ec292018-06-01 15:35:421932 ProtocolParser::Results results;
1933 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:031934 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:461935 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
1936 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:031937 }
1938 };
1939
Sorin Jianua8926bf2018-03-09 21:02:531940 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:031941 public:
dchengd0fc6aa92016-04-22 18:03:121942 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:031943 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:121944 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:531945 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:031946 }
1947
Sorin Jianua8926bf2018-03-09 21:02:531948 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:031949
sorin30474f02017-04-27 00:45:481950 private:
sorin9797aba2015-04-17 17:15:031951 void DoStartDownload(const GURL& url) override {
1952 DownloadMetrics download_metrics;
1953 download_metrics.url = url;
1954 download_metrics.downloader = DownloadMetrics::kNone;
1955 download_metrics.error = 0;
1956 download_metrics.downloaded_bytes = 1843;
1957 download_metrics.total_bytes = 1843;
1958 download_metrics.download_time_ms = 1000;
1959
1960 FilePath path;
1961 EXPECT_TRUE(MakeTestFile(
1962 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
1963
1964 Result result;
1965 result.error = 0;
1966 result.response = path;
sorin9797aba2015-04-17 17:15:031967
1968 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531969 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:031970 base::Unretained(this)));
sorin9797aba2015-04-17 17:15:031971
1972 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:531973 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:581974 base::Unretained(this), true, result,
1975 download_metrics));
sorin9797aba2015-04-17 17:15:031976 }
1977 };
1978
Sorin Jianua8926bf2018-03-09 21:02:531979 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:031980 public:
Sorin Jianua8926bf2018-03-09 21:02:531981 explicit MockPingManager(scoped_refptr<Configurator> config)
1982 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:541983
1984 protected:
Sorin Jianua8926bf2018-03-09 21:02:531985 ~MockPingManager() override {
1986 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:481987 EXPECT_EQ(1u, ping_data.size());
1988 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
1989 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
1990 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:101991 EXPECT_EQ(3, static_cast<int>(ping_data[0].error_category)); // kInstall.
1992 EXPECT_EQ(9, ping_data[0].error_code); // kInstallerError.
sorin9797aba2015-04-17 17:15:031993 }
1994 };
1995
sorin30474f02017-04-27 00:45:481996 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:431997 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:531998 config(), base::MakeRefCounted<MockPingManager>(config()),
1999 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:032000
2001 MockObserver observer;
2002 {
2003 InSequence seq;
2004 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2005 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2006 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2007 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
2008 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482009 "jebgalgnebhfojomionfpkfelancnnkf"))
2010 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:032011 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2012 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
Sorin Jianucbb10e12018-01-23 18:01:442013 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
2014 "jebgalgnebhfojomionfpkfelancnnkf"))
2015 .Times(1);
sorin9797aba2015-04-17 17:15:032016 }
2017
Sorin Jianudfb12a42020-03-10 04:12:032018 std::vector<CrxUpdateItem> items;
2019 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2020 EXPECT_CALL(*receiver, Receive(_))
2021 .WillRepeatedly(
2022 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin9797aba2015-04-17 17:15:032023
Sorin Jianudfb12a42020-03-10 04:12:032024 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:482025 std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin9797aba2015-04-17 17:15:032026 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:032027 ids, base::BindOnce(&DataCallbackMock::Callback),
2028 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
2029 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin9797aba2015-04-17 17:15:032030 RunThreads();
2031
Sorin Jianudfb12a42020-03-10 04:12:032032 EXPECT_EQ(6u, items.size());
2033 EXPECT_EQ(ComponentState::kChecking, items[0].state);
2034 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
2035 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
2036 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[1].id.c_str());
2037 EXPECT_EQ(ComponentState::kDownloading, items[2].state);
2038 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
2039 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
2040 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
2041 EXPECT_EQ(ComponentState::kUpdating, items[4].state);
2042 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
2043 EXPECT_EQ(ComponentState::kUpdateError, items[5].state);
2044 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
2045
sorin9797aba2015-04-17 17:15:032046 update_client->RemoveObserver(&observer);
2047}
2048
2049// Tests the fallback from differential to full update scenario for one CRX.
2050TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
Sorin Jianua8926bf2018-03-09 21:02:532051 class DataCallbackMock {
sorin9797aba2015-04-17 17:15:032052 public:
Sorin Jianu73900242018-08-17 01:11:532053 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:522054 const std::vector<std::string>& ids) {
sorin9797aba2015-04-17 17:15:032055 static int num_calls = 0;
2056
2057 // Must use the same stateful installer object.
sorin30474f02017-04-27 00:45:482058 static scoped_refptr<CrxInstaller> installer =
Taiju Tsuiki36c517d2017-05-18 06:45:432059 base::MakeRefCounted<VersionedTestInstaller>();
sorin9797aba2015-04-17 17:15:032060
2061 ++num_calls;
2062
Sorin Jianu73900242018-08-17 01:11:532063 CrxComponent crx;
2064 crx.name = "test_ihfo";
2065 crx.pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
2066 crx.installer = installer;
Joshua Pawlickiafaa2922019-09-03 18:50:232067 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorin9797aba2015-04-17 17:15:032068 if (num_calls == 1) {
Sorin Jianu73900242018-08-17 01:11:532069 crx.version = base::Version("0.8");
sorin9797aba2015-04-17 17:15:032070 } else if (num_calls == 2) {
Sorin Jianu73900242018-08-17 01:11:532071 crx.version = base::Version("1.0");
sorin9797aba2015-04-17 17:15:032072 } else {
2073 NOTREACHED();
2074 }
2075
Sorin Jianu73900242018-08-17 01:11:532076 return {crx};
sorin9797aba2015-04-17 17:15:032077 }
2078 };
2079
Sorin Jianua8926bf2018-03-09 21:02:532080 class CompletionCallbackMock {
sorin9797aba2015-04-17 17:15:032081 public:
Sorin Jianua8ef73d2017-11-02 16:55:172082 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:412083 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172084 std::move(quit_closure).Run();
sorin9797aba2015-04-17 17:15:032085 }
2086 };
2087
Sorin Jianua8926bf2018-03-09 21:02:532088 class MockUpdateChecker : public UpdateChecker {
sorin9797aba2015-04-17 17:15:032089 public:
dchengd0fc6aa92016-04-22 18:03:122090 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422091 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492092 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532093 return std::make_unique<MockUpdateChecker>();
sorin9797aba2015-04-17 17:15:032094 }
2095
Sorin Jianuc303bf42018-09-07 16:19:332096 void CheckForUpdates(
2097 const std::string& session_id,
2098 const std::vector<std::string>& ids_to_check,
2099 const IdToComponentPtrMap& components,
2100 const base::flat_map<std::string, std::string>& additional_attributes,
2101 bool enabled_component_updates,
2102 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222103 EXPECT_FALSE(session_id.empty());
2104
sorin9797aba2015-04-17 17:15:032105 static int num_call = 0;
2106 ++num_call;
2107
sorin7cff6e52017-05-17 16:37:232108 ProtocolParser::Results results;
sorin9797aba2015-04-17 17:15:032109
2110 if (num_call == 1) {
2111 /*
Sorin Jianua8926bf2018-03-09 21:02:532112 Mock the following response:
sorin9797aba2015-04-17 17:15:032113 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282114 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:032115 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
2116 <updatecheck status='ok'>
2117 <urls>
2118 <url codebase='http://localhost/download/'/>
2119 </urls>
2120 <manifest version='1.0' prodversionmin='11.0.1.0'>
2121 <packages>
sorin74e70672016-02-03 03:13:102122 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
2123 hash_sha256='813c59747e139a608b3b5fc49633affc6db57437
sorin30474f02017-04-27 00:45:482124 3f309f156ea6d27229c0b3f9'
2125 fp='1'/>
sorin9797aba2015-04-17 17:15:032126 </packages>
2127 </manifest>
2128 </updatecheck>
2129 </app>
2130 </response>
2131 */
sorin30474f02017-04-27 00:45:482132 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
2133 EXPECT_EQ(id, ids_to_check[0]);
2134 EXPECT_EQ(1u, components.count(id));
2135
sorin7cff6e52017-05-17 16:37:232136 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:032137 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
sorin74e70672016-02-03 03:13:102138 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:232139 "8f5aa190311237cae00675af87ff457f278cd1a05895470ac5d46647d4a3c2ea";
sorin9797aba2015-04-17 17:15:032140 package.fingerprint = "1";
sorin30474f02017-04-27 00:45:482141
sorin7cff6e52017-05-17 16:37:232142 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482143 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:172144 result.status = "ok";
sorin9797aba2015-04-17 17:15:032145 result.crx_urls.push_back(GURL("http://localhost/download/"));
2146 result.manifest.version = "1.0";
2147 result.manifest.browser_min_version = "11.0.1.0";
2148 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:422149 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:032150 } else if (num_call == 2) {
2151 /*
Sorin Jianua8926bf2018-03-09 21:02:532152 Mock the following response:
sorin9797aba2015-04-17 17:15:032153 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282154 <response protocol='3.1'>
sorin9797aba2015-04-17 17:15:032155 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
2156 <updatecheck status='ok'>
2157 <urls>
2158 <url codebase='http://localhost/download/'/>
2159 <url codebasediff='http://localhost/download/'/>
2160 </urls>
2161 <manifest version='2.0' prodversionmin='11.0.1.0'>
2162 <packages>
2163 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
2164 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:232165 hash_sha256='c87d8742c3ff3d7a0cb6f3c91aa2fcf3dea6361
2166 8086a7db1c5be5300e1d4d6b6'
sorin74e70672016-02-03 03:13:102167 fp='22'
Joshua Pawlickiafaa2922019-09-03 18:50:232168 hashdiff_sha256='0fd48a5dd87006a709756cfc47198cbc4c4
2169 928f33ac4277d79573c15164a33eb'/>
sorin9797aba2015-04-17 17:15:032170 </packages>
2171 </manifest>
2172 </updatecheck>
2173 </app>
2174 </response>
2175 */
sorin30474f02017-04-27 00:45:482176 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
2177 EXPECT_EQ(id, ids_to_check[0]);
2178 EXPECT_EQ(1u, components.count(id));
2179
sorin7cff6e52017-05-17 16:37:232180 ProtocolParser::Result::Manifest::Package package;
sorin9797aba2015-04-17 17:15:032181 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
2182 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
sorin74e70672016-02-03 03:13:102183 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:232184 "c87d8742c3ff3d7a0cb6f3c91aa2fcf3dea63618086a7db1c5be5300e1d4d6b6";
sorin74e70672016-02-03 03:13:102185 package.hashdiff_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:232186 "0fd48a5dd87006a709756cfc47198cbc4c4928f33ac4277d79573c15164a33eb";
sorin9797aba2015-04-17 17:15:032187 package.fingerprint = "22";
sorin30474f02017-04-27 00:45:482188
sorin7cff6e52017-05-17 16:37:232189 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482190 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:172191 result.status = "ok";
sorin9797aba2015-04-17 17:15:032192 result.crx_urls.push_back(GURL("http://localhost/download/"));
2193 result.crx_diffurls.push_back(GURL("http://localhost/download/"));
2194 result.manifest.version = "2.0";
2195 result.manifest.browser_min_version = "11.0.1.0";
2196 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:422197 results.list.push_back(result);
sorin9797aba2015-04-17 17:15:032198 } else {
2199 NOTREACHED();
2200 }
2201
2202 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462203 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2204 ErrorCategory::kNone, 0, 0));
sorin9797aba2015-04-17 17:15:032205 }
2206 };
2207
Sorin Jianua8926bf2018-03-09 21:02:532208 class MockCrxDownloader : public CrxDownloader {
sorin9797aba2015-04-17 17:15:032209 public:
dchengd0fc6aa92016-04-22 18:03:122210 static std::unique_ptr<CrxDownloader> Create(
sorin9797aba2015-04-17 17:15:032211 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:122212 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:532213 return std::make_unique<MockCrxDownloader>();
sorin9797aba2015-04-17 17:15:032214 }
2215
Sorin Jianua8926bf2018-03-09 21:02:532216 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin9797aba2015-04-17 17:15:032217
sorin30474f02017-04-27 00:45:482218 private:
sorin9797aba2015-04-17 17:15:032219 void DoStartDownload(const GURL& url) override {
2220 DownloadMetrics download_metrics;
2221 FilePath path;
2222 Result result;
2223 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
2224 download_metrics.url = url;
2225 download_metrics.downloader = DownloadMetrics::kNone;
2226 download_metrics.error = 0;
2227 download_metrics.downloaded_bytes = 53638;
2228 download_metrics.total_bytes = 53638;
2229 download_metrics.download_time_ms = 2000;
2230
2231 EXPECT_TRUE(MakeTestFile(
2232 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
2233
2234 result.error = 0;
2235 result.response = path;
sorin9797aba2015-04-17 17:15:032236 } else if (url.path() ==
2237 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
2238 // A download error is injected on this execution path.
2239 download_metrics.url = url;
2240 download_metrics.downloader = DownloadMetrics::kNone;
2241 download_metrics.error = -1;
2242 download_metrics.downloaded_bytes = 0;
2243 download_metrics.total_bytes = 2105;
2244 download_metrics.download_time_ms = 1000;
2245
Sorin Jianu52de5fa2017-10-09 23:19:332246 // The response must not include a file path in the case of errors.
sorin9797aba2015-04-17 17:15:032247 result.error = -1;
sorin9797aba2015-04-17 17:15:032248 } else if (url.path() ==
2249 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
2250 download_metrics.url = url;
2251 download_metrics.downloader = DownloadMetrics::kNone;
2252 download_metrics.error = 0;
2253 download_metrics.downloaded_bytes = 53855;
2254 download_metrics.total_bytes = 53855;
2255 download_metrics.download_time_ms = 1000;
2256
2257 EXPECT_TRUE(MakeTestFile(
2258 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
2259
2260 result.error = 0;
2261 result.response = path;
sorin9797aba2015-04-17 17:15:032262 }
2263
2264 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532265 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:032266 base::Unretained(this)));
sorin9797aba2015-04-17 17:15:032267
2268 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532269 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582270 base::Unretained(this), true, result,
2271 download_metrics));
sorin9797aba2015-04-17 17:15:032272 }
2273 };
2274
Sorin Jianua8926bf2018-03-09 21:02:532275 class MockPingManager : public MockPingManagerImpl {
sorin9797aba2015-04-17 17:15:032276 public:
Sorin Jianua8926bf2018-03-09 21:02:532277 explicit MockPingManager(scoped_refptr<Configurator> config)
2278 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542279
2280 protected:
Sorin Jianua8926bf2018-03-09 21:02:532281 ~MockPingManager() override {
2282 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482283 EXPECT_EQ(2u, ping_data.size());
2284 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
2285 EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
2286 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102287 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:482288 EXPECT_EQ(0, ping_data[0].error_code);
2289 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
2290 EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
2291 EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102292 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:482293 EXPECT_EQ(0, ping_data[1].error_code);
2294 EXPECT_TRUE(ping_data[1].diff_update_failed);
Minh X. Nguyena4640cb2018-05-23 21:29:102295 EXPECT_EQ(1, static_cast<int>(ping_data[1].diff_error_category));
sorin30474f02017-04-27 00:45:482296 EXPECT_EQ(-1, ping_data[1].diff_error_code);
sorin9797aba2015-04-17 17:15:032297 }
2298 };
2299
sorin30474f02017-04-27 00:45:482300 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432301 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532302 config(), base::MakeRefCounted<MockPingManager>(config()),
2303 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin9797aba2015-04-17 17:15:032304
2305 MockObserver observer;
2306 {
2307 InSequence seq;
2308 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2309 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2310 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2311 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2312 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482313 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2314 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:032315 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2316 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2317 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2318 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2319
2320 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2321 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2322 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2323 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2324 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
sorin30474f02017-04-27 00:45:482325 "ihfokbkgjpifnbbojhneepfflplebdkc"))
2326 .Times(AtLeast(1));
sorin9797aba2015-04-17 17:15:032327 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2328 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2329 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2330 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
2331 }
2332
2333 update_client->AddObserver(&observer);
2334
sorin30474f02017-04-27 00:45:482335 const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"};
sorin9797aba2015-04-17 17:15:032336
2337 {
Sorin Jianudfb12a42020-03-10 04:12:032338 std::vector<CrxUpdateItem> items;
2339 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2340 EXPECT_CALL(*receiver, Receive(_))
2341 .WillRepeatedly(
2342 [&items](const CrxUpdateItem& item) { items.push_back(item); });
2343
sorin9797aba2015-04-17 17:15:032344 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:032345 update_client->Update(
2346 ids, base::BindOnce(&DataCallbackMock::Callback),
2347 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
2348 false,
2349 base::BindOnce(&CompletionCallbackMock::Callback,
2350 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:032351 runloop.Run();
Sorin Jianudfb12a42020-03-10 04:12:032352 EXPECT_EQ(6u, items.size());
2353 EXPECT_EQ(ComponentState::kChecking, items[0].state);
2354 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[0].id.c_str());
2355 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
2356 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
2357 EXPECT_EQ(ComponentState::kDownloading, items[2].state);
2358 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[2].id.c_str());
2359 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
2360 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[3].id.c_str());
2361 EXPECT_EQ(ComponentState::kUpdating, items[4].state);
2362 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[4].id.c_str());
2363 EXPECT_EQ(ComponentState::kUpdated, items[5].state);
2364 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[5].id.c_str());
sorin9797aba2015-04-17 17:15:032365 }
2366
2367 {
Sorin Jianudfb12a42020-03-10 04:12:032368 std::vector<CrxUpdateItem> items;
2369 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2370 EXPECT_CALL(*receiver, Receive(_))
2371 .WillRepeatedly(
2372 [&items](const CrxUpdateItem& item) { items.push_back(item); });
2373
sorin9797aba2015-04-17 17:15:032374 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:032375 update_client->Update(
2376 ids, base::BindOnce(&DataCallbackMock::Callback),
2377 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
2378 false,
2379 base::BindOnce(&CompletionCallbackMock::Callback,
2380 runloop.QuitClosure()));
sorin9797aba2015-04-17 17:15:032381 runloop.Run();
Sorin Jianudfb12a42020-03-10 04:12:032382
2383 EXPECT_EQ(8u, items.size());
2384 EXPECT_EQ(ComponentState::kChecking, items[0].state);
2385 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[0].id.c_str());
2386 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
2387 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
2388 EXPECT_EQ(ComponentState::kDownloadingDiff, items[2].state);
2389 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[2].id.c_str());
2390 EXPECT_EQ(ComponentState::kDownloadingDiff, items[3].state);
2391 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[3].id.c_str());
2392 EXPECT_EQ(ComponentState::kDownloading, items[4].state);
2393 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[4].id.c_str());
2394 EXPECT_EQ(ComponentState::kDownloading, items[5].state);
2395 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[5].id.c_str());
2396 EXPECT_EQ(ComponentState::kUpdating, items[6].state);
2397 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[6].id.c_str());
2398 EXPECT_EQ(ComponentState::kUpdated, items[7].state);
2399 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[7].id.c_str());
sorin9797aba2015-04-17 17:15:032400 }
2401
2402 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:092403}
2404
2405// Tests the queuing of update checks. In this scenario, two update checks are
2406// done for one CRX. The second update check call is queued up and will run
2407// after the first check has completed. The CRX has no updates.
2408TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
Sorin Jianua8926bf2018-03-09 21:02:532409 class DataCallbackMock {
sorin7c717622015-05-26 19:59:092410 public:
Sorin Jianu73900242018-08-17 01:11:532411 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:522412 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:532413 CrxComponent crx;
2414 crx.name = "test_jebg";
2415 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
2416 crx.version = base::Version("0.9");
2417 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:232418 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:532419 return {crx};
sorin7c717622015-05-26 19:59:092420 }
2421 };
2422
Sorin Jianua8926bf2018-03-09 21:02:532423 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:092424 public:
Sorin Jianua8ef73d2017-11-02 16:55:172425 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7c717622015-05-26 19:59:092426 static int num_call = 0;
2427 ++num_call;
2428
sorin7b8650522016-11-02 18:23:412429 EXPECT_EQ(Error::NONE, error);
sorin7c717622015-05-26 19:59:092430
2431 if (num_call == 2)
Sorin Jianua8ef73d2017-11-02 16:55:172432 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:092433 }
2434 };
2435
Sorin Jianua8926bf2018-03-09 21:02:532436 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:092437 public:
dchengd0fc6aa92016-04-22 18:03:122438 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422439 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492440 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532441 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:092442 }
2443
Sorin Jianuc303bf42018-09-07 16:19:332444 void CheckForUpdates(
2445 const std::string& session_id,
2446 const std::vector<std::string>& ids_to_check,
2447 const IdToComponentPtrMap& components,
2448 const base::flat_map<std::string, std::string>& additional_attributes,
2449 bool enabled_component_updates,
2450 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222451 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482452 EXPECT_TRUE(enabled_component_updates);
2453 EXPECT_EQ(1u, ids_to_check.size());
2454 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2455 EXPECT_EQ(id, ids_to_check.front());
2456 EXPECT_EQ(1u, components.count(id));
2457
2458 auto& component = components.at(id);
2459
Sorin Jianub41a592a2018-03-02 16:30:272460 EXPECT_FALSE(component->is_foreground());
sorin30474f02017-04-27 00:45:482461
sorin7cff6e52017-05-17 16:37:232462 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482463 result.extension_id = id;
2464 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:422465 ProtocolParser::Results results;
2466 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482467
sorin7c717622015-05-26 19:59:092468 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462469 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2470 ErrorCategory::kNone, 0, 0));
sorin7c717622015-05-26 19:59:092471 }
2472 };
2473
Sorin Jianua8926bf2018-03-09 21:02:532474 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092475 public:
dchengd0fc6aa92016-04-22 18:03:122476 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092477 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:122478 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:532479 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092480 }
2481
Sorin Jianua8926bf2018-03-09 21:02:532482 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092483
sorin30474f02017-04-27 00:45:482484 private:
sorin7c717622015-05-26 19:59:092485 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2486 };
2487
Sorin Jianua8926bf2018-03-09 21:02:532488 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092489 public:
Sorin Jianua8926bf2018-03-09 21:02:532490 explicit MockPingManager(scoped_refptr<Configurator> config)
2491 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542492
2493 protected:
Sorin Jianua8926bf2018-03-09 21:02:532494 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin7c717622015-05-26 19:59:092495 };
2496
sorin30474f02017-04-27 00:45:482497 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432498 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532499 config(), base::MakeRefCounted<MockPingManager>(config()),
2500 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin7c717622015-05-26 19:59:092501
2502 MockObserver observer;
Sorin Jianudfb12a42020-03-10 04:12:032503 {
2504 InSequence seq;
2505 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2506 "jebgalgnebhfojomionfpkfelancnnkf"))
2507 .Times(1);
2508 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2509 "jebgalgnebhfojomionfpkfelancnnkf"))
2510 .Times(1);
2511 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2512 "jebgalgnebhfojomionfpkfelancnnkf"))
2513 .Times(1);
2514 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
2515 "jebgalgnebhfojomionfpkfelancnnkf"))
2516 .Times(1);
2517 }
2518
2519 std::vector<CrxUpdateItem> items1;
2520 auto receiver1 = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2521 EXPECT_CALL(*receiver1, Receive(_))
2522 .WillRepeatedly(
2523 [&items1](const CrxUpdateItem& item) { items1.push_back(item); });
2524
2525 std::vector<CrxUpdateItem> items2;
2526 auto receiver2 = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2527 EXPECT_CALL(*receiver2, Receive(_))
2528 .WillRepeatedly(
2529 [&items2](const CrxUpdateItem& item) { items2.push_back(item); });
sorin7c717622015-05-26 19:59:092530
2531 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:482532 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorin7c717622015-05-26 19:59:092533 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:032534 ids, base::BindOnce(&DataCallbackMock::Callback),
2535 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver1),
2536 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092537 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:032538 ids, base::BindOnce(&DataCallbackMock::Callback),
2539 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver2),
2540 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092541 RunThreads();
2542
Sorin Jianudfb12a42020-03-10 04:12:032543 EXPECT_EQ(2u, items1.size());
2544 EXPECT_EQ(ComponentState::kChecking, items1[0].state);
2545 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items1[0].id.c_str());
2546 EXPECT_EQ(ComponentState::kUpToDate, items1[1].state);
2547 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items1[1].id.c_str());
2548
2549 EXPECT_EQ(2u, items2.size());
2550 EXPECT_EQ(ComponentState::kChecking, items2[0].state);
2551 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items2[0].id.c_str());
2552 EXPECT_EQ(ComponentState::kUpToDate, items2[1].state);
2553 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items2[1].id.c_str());
2554
sorin7c717622015-05-26 19:59:092555 update_client->RemoveObserver(&observer);
sorin7c717622015-05-26 19:59:092556}
2557
Sorin Jianu9d64af672020-02-05 19:14:342558// Tests the install of one CRX. Tests the installer is invoked with the
Sorin Jianub9258672020-02-19 16:52:172559// run and arguments values of the manifest object. Tests that "pv" and "fp"
2560// are persisted.
sorin7c717622015-05-26 19:59:092561TEST_F(UpdateClientTest, OneCrxInstall) {
Sorin Jianua8926bf2018-03-09 21:02:532562 class DataCallbackMock {
sorin7c717622015-05-26 19:59:092563 public:
Sorin Jianu73900242018-08-17 01:11:532564 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:522565 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:532566 CrxComponent crx;
2567 crx.name = "test_jebg";
2568 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
2569 crx.version = base::Version("0.0");
2570 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:232571 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:532572 return {crx};
sorin7c717622015-05-26 19:59:092573 }
2574 };
2575
Sorin Jianua8926bf2018-03-09 21:02:532576 class CompletionCallbackMock {
sorin7c717622015-05-26 19:59:092577 public:
Sorin Jianua8ef73d2017-11-02 16:55:172578 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:412579 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172580 std::move(quit_closure).Run();
sorin7c717622015-05-26 19:59:092581 }
2582 };
2583
Sorin Jianua8926bf2018-03-09 21:02:532584 class MockUpdateChecker : public UpdateChecker {
sorin7c717622015-05-26 19:59:092585 public:
dchengd0fc6aa92016-04-22 18:03:122586 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422587 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492588 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532589 return std::make_unique<MockUpdateChecker>();
sorin7c717622015-05-26 19:59:092590 }
2591
Sorin Jianuc303bf42018-09-07 16:19:332592 void CheckForUpdates(
2593 const std::string& session_id,
2594 const std::vector<std::string>& ids_to_check,
2595 const IdToComponentPtrMap& components,
2596 const base::flat_map<std::string, std::string>& additional_attributes,
2597 bool enabled_component_updates,
2598 UpdateCheckCallback update_check_callback) override {
sorin7c717622015-05-26 19:59:092599 /*
Sorin Jianua8926bf2018-03-09 21:02:532600 Mock the following response:
sorin7c717622015-05-26 19:59:092601
2602 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:282603 <response protocol='3.1'>
sorin7c717622015-05-26 19:59:092604 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
2605 <updatecheck status='ok'>
2606 <urls>
2607 <url codebase='http://localhost/download/'/>
2608 </urls>
Sorin Jianu9d64af672020-02-05 19:14:342609 <manifest version='1.0' prodversionmin='11.0.1.0'
2610 run='UpdaterSetup.exe' arguments='--arg1 --arg2'>
sorin7c717622015-05-26 19:59:092611 <packages>
sorin74e70672016-02-03 03:13:102612 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:232613 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
2614 a284a7cd8059c3409ce0498'/>
sorin7c717622015-05-26 19:59:092615 </packages>
2616 </manifest>
2617 </updatecheck>
2618 </app>
2619 </response>
2620 */
Sorin Jianud69d4372018-02-07 19:44:222621 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482622 EXPECT_TRUE(enabled_component_updates);
2623 EXPECT_EQ(1u, ids_to_check.size());
2624
2625 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2626 EXPECT_EQ(id, ids_to_check[0]);
2627 EXPECT_EQ(1u, components.count(id));
2628
sorin7cff6e52017-05-17 16:37:232629 ProtocolParser::Result::Manifest::Package package;
sorin7c717622015-05-26 19:59:092630 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
sorin74e70672016-02-03 03:13:102631 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:232632 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
Sorin Jianub9258672020-02-19 16:52:172633 package.fingerprint = "some-fingerprint";
sorin30474f02017-04-27 00:45:482634
sorin7cff6e52017-05-17 16:37:232635 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482636 result.extension_id = id;
sorin9ef301c2017-02-16 20:29:172637 result.status = "ok";
sorin7c717622015-05-26 19:59:092638 result.crx_urls.push_back(GURL("http://localhost/download/"));
2639 result.manifest.version = "1.0";
2640 result.manifest.browser_min_version = "11.0.1.0";
Sorin Jianu9d64af672020-02-05 19:14:342641 result.manifest.run = "UpdaterSetup.exe";
2642 result.manifest.arguments = "--arg1 --arg2";
sorin7c717622015-05-26 19:59:092643 result.manifest.packages.push_back(package);
2644
Sorin Jianu888ec292018-06-01 15:35:422645 ProtocolParser::Results results;
2646 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482647
2648 // Verify that calling Install sets ondemand.
Sorin Jianu888ec292018-06-01 15:35:422649 EXPECT_TRUE(components.at(id)->is_foreground());
sorin7c717622015-05-26 19:59:092650
2651 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462652 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2653 ErrorCategory::kNone, 0, 0));
sorin7c717622015-05-26 19:59:092654 }
2655 };
2656
Sorin Jianua8926bf2018-03-09 21:02:532657 class MockCrxDownloader : public CrxDownloader {
sorin7c717622015-05-26 19:59:092658 public:
dchengd0fc6aa92016-04-22 18:03:122659 static std::unique_ptr<CrxDownloader> Create(
sorin7c717622015-05-26 19:59:092660 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:122661 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:532662 return std::make_unique<MockCrxDownloader>();
sorin7c717622015-05-26 19:59:092663 }
2664
Sorin Jianua8926bf2018-03-09 21:02:532665 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin7c717622015-05-26 19:59:092666
sorin30474f02017-04-27 00:45:482667 private:
sorin7c717622015-05-26 19:59:092668 void DoStartDownload(const GURL& url) override {
2669 DownloadMetrics download_metrics;
2670 FilePath path;
2671 Result result;
2672 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
2673 download_metrics.url = url;
2674 download_metrics.downloader = DownloadMetrics::kNone;
2675 download_metrics.error = 0;
2676 download_metrics.downloaded_bytes = 1843;
2677 download_metrics.total_bytes = 1843;
2678 download_metrics.download_time_ms = 1000;
2679
2680 EXPECT_TRUE(MakeTestFile(
2681 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
2682
2683 result.error = 0;
2684 result.response = path;
sorin7c717622015-05-26 19:59:092685 } else {
2686 NOTREACHED();
2687 }
2688
2689 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532690 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:032691 base::Unretained(this)));
sorin7c717622015-05-26 19:59:092692
2693 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:532694 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:582695 base::Unretained(this), true, result,
2696 download_metrics));
sorin7c717622015-05-26 19:59:092697 }
2698 };
2699
Sorin Jianua8926bf2018-03-09 21:02:532700 class MockPingManager : public MockPingManagerImpl {
sorin7c717622015-05-26 19:59:092701 public:
Sorin Jianua8926bf2018-03-09 21:02:532702 explicit MockPingManager(scoped_refptr<Configurator> config)
2703 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:542704
2705 protected:
Sorin Jianua8926bf2018-03-09 21:02:532706 ~MockPingManager() override {
2707 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:482708 EXPECT_EQ(1u, ping_data.size());
2709 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
2710 EXPECT_EQ(base::Version("0.0"), ping_data[0].previous_version);
2711 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:102712 EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:482713 EXPECT_EQ(0, ping_data[0].error_code);
sorin7c717622015-05-26 19:59:092714 }
2715 };
2716
sorin30474f02017-04-27 00:45:482717 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:432718 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:532719 config(), base::MakeRefCounted<MockPingManager>(config()),
2720 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianub9258672020-02-19 16:52:172721 {
2722 EXPECT_FALSE(config()->GetPrefService()->FindPreference(
2723 "updateclientdata.apps.jebgalgnebhfojomionfpkfelancnnkf.pv"));
2724 EXPECT_FALSE(config()->GetPrefService()->FindPreference(
2725 "updateclientdata.apps.jebgalgnebhfojomionfpkfelancnnkf.fp"));
2726 }
sorin7c717622015-05-26 19:59:092727
2728 MockObserver observer;
Sorin Jianudfb12a42020-03-10 04:12:032729 {
2730 InSequence seq;
2731 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
2732 "jebgalgnebhfojomionfpkfelancnnkf"))
2733 .Times(1);
2734 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
2735 "jebgalgnebhfojomionfpkfelancnnkf"))
2736 .Times(1);
2737 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
2738 "jebgalgnebhfojomionfpkfelancnnkf"))
2739 .Times(AtLeast(1));
2740 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
2741 "jebgalgnebhfojomionfpkfelancnnkf"))
2742 .Times(1);
2743 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
2744 "jebgalgnebhfojomionfpkfelancnnkf"))
2745 .Times(1)
2746 .WillOnce(Invoke([update_client](Events event, const std::string& id) {
2747 CrxUpdateItem update_item;
2748 ASSERT_TRUE(update_client->GetCrxUpdateState(id, &update_item));
2749 ASSERT_TRUE(update_item.component);
2750 const auto* test_installer = static_cast<TestInstaller*>(
2751 update_item.component->installer.get());
2752 EXPECT_STREQ("UpdaterSetup.exe",
2753 test_installer->install_params()->run.c_str());
2754 EXPECT_STREQ("--arg1 --arg2",
2755 test_installer->install_params()->arguments.c_str());
2756 }));
2757 }
2758
2759 std::vector<CrxUpdateItem> items;
2760 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2761 EXPECT_CALL(*receiver, Receive(_))
2762 .WillRepeatedly(
2763 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin7c717622015-05-26 19:59:092764
2765 update_client->AddObserver(&observer);
sorin7c717622015-05-26 19:59:092766 update_client->Install(
2767 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:532768 base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianudfb12a42020-03-10 04:12:032769 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
Sorin Jianua8926bf2018-03-09 21:02:532770 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin7c717622015-05-26 19:59:092771 RunThreads();
2772
Sorin Jianudfb12a42020-03-10 04:12:032773 EXPECT_EQ(6u, items.size());
2774 EXPECT_EQ(ComponentState::kChecking, items[0].state);
2775 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
2776 EXPECT_EQ(ComponentState::kCanUpdate, items[1].state);
2777 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[1].id.c_str());
2778 EXPECT_EQ(ComponentState::kDownloading, items[2].state);
2779 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
2780 EXPECT_EQ(ComponentState::kDownloading, items[3].state);
2781 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
2782 EXPECT_EQ(ComponentState::kUpdating, items[4].state);
2783 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[4].id.c_str());
2784 EXPECT_EQ(ComponentState::kUpdated, items[5].state);
2785 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
2786
Sorin Jianub9258672020-02-19 16:52:172787 const base::DictionaryValue* dict =
2788 config()->GetPrefService()->GetDictionary("updateclientdata");
2789 std::string pv;
2790 dict->GetString("apps.jebgalgnebhfojomionfpkfelancnnkf.pv", &pv);
2791 EXPECT_STREQ("1.0", pv.c_str());
2792 std::string fingerprint;
2793 dict->GetString("apps.jebgalgnebhfojomionfpkfelancnnkf.fp", &fingerprint);
2794 EXPECT_STREQ("some-fingerprint", fingerprint.c_str());
2795
sorin7c717622015-05-26 19:59:092796 update_client->RemoveObserver(&observer);
sorin9797aba2015-04-17 17:15:032797}
2798
Sorin Jianucb4431a2018-04-30 20:59:242799// Tests the install of one CRX when no component data is provided. This
2800// results in an install error.
2801TEST_F(UpdateClientTest, OneCrxInstallNoCrxComponentData) {
2802 class DataCallbackMock {
2803 public:
Sorin Jianu73900242018-08-17 01:11:532804 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianucb4431a2018-04-30 20:59:242805 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:532806 return {base::nullopt};
Sorin Jianucb4431a2018-04-30 20:59:242807 }
2808 };
2809
2810 class CompletionCallbackMock {
2811 public:
2812 static void Callback(base::OnceClosure quit_closure, Error error) {
2813 EXPECT_EQ(Error::NONE, error);
2814 std::move(quit_closure).Run();
2815 }
2816 };
2817
2818 class MockUpdateChecker : public UpdateChecker {
2819 public:
2820 static std::unique_ptr<UpdateChecker> Create(
2821 scoped_refptr<Configurator> config,
2822 PersistedData* metadata) {
2823 return std::make_unique<MockUpdateChecker>();
2824 }
2825
Sorin Jianuc303bf42018-09-07 16:19:332826 void CheckForUpdates(
2827 const std::string& session_id,
2828 const std::vector<std::string>& ids_to_check,
2829 const IdToComponentPtrMap& components,
2830 const base::flat_map<std::string, std::string>& additional_attributes,
2831 bool enabled_component_updates,
2832 UpdateCheckCallback update_check_callback) override {
Sorin Jianucb4431a2018-04-30 20:59:242833 NOTREACHED();
2834 }
2835 };
2836
2837 class MockCrxDownloader : public CrxDownloader {
2838 public:
2839 static std::unique_ptr<CrxDownloader> Create(
2840 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:122841 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianucb4431a2018-04-30 20:59:242842 return std::make_unique<MockCrxDownloader>();
2843 }
2844
2845 MockCrxDownloader() : CrxDownloader(nullptr) {}
2846
2847 private:
2848 void DoStartDownload(const GURL& url) override { NOTREACHED(); }
2849 };
2850
2851 class MockPingManager : public MockPingManagerImpl {
2852 public:
2853 explicit MockPingManager(scoped_refptr<Configurator> config)
2854 : MockPingManagerImpl(config) {}
2855
2856 protected:
2857 ~MockPingManager() override {
2858 EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
2859 }
2860 };
2861
2862 scoped_refptr<UpdateClient> update_client =
2863 base::MakeRefCounted<UpdateClientImpl>(
2864 config(), base::MakeRefCounted<MockPingManager>(config()),
2865 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
2866
2867 MockObserver observer;
Sorin Jianudfb12a42020-03-10 04:12:032868 {
2869 InSequence seq;
2870 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
2871 "jebgalgnebhfojomionfpkfelancnnkf"))
2872 .Times(1)
2873 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
2874 // Tests that the state of the component when the CrxComponent data
2875 // is not provided. In this case, the optional |item.component|
2876 // instance is not present.
2877 CrxUpdateItem item;
2878 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
2879 EXPECT_EQ(ComponentState::kUpdateError, item.state);
2880 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", item.id.c_str());
2881 EXPECT_FALSE(item.component);
2882 EXPECT_EQ(ErrorCategory::kService, item.error_category);
2883 EXPECT_EQ(static_cast<int>(Error::CRX_NOT_FOUND), item.error_code);
2884 EXPECT_EQ(0, item.extra_code1);
2885 }));
2886 }
2887
2888 std::vector<CrxUpdateItem> items;
2889 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
2890 EXPECT_CALL(*receiver, Receive(_))
2891 .WillRepeatedly(
2892 [&items](const CrxUpdateItem& item) { items.push_back(item); });
Sorin Jianucb4431a2018-04-30 20:59:242893
2894 update_client->AddObserver(&observer);
Sorin Jianucb4431a2018-04-30 20:59:242895 update_client->Install(
2896 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
2897 base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianudfb12a42020-03-10 04:12:032898 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
Sorin Jianucb4431a2018-04-30 20:59:242899 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
Sorin Jianucb4431a2018-04-30 20:59:242900 RunThreads();
2901
Sorin Jianudfb12a42020-03-10 04:12:032902 EXPECT_EQ(1u, items.size());
2903 EXPECT_EQ(ComponentState::kUpdateError, items[0].state);
2904 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
2905
Sorin Jianucb4431a2018-04-30 20:59:242906 update_client->RemoveObserver(&observer);
2907}
2908
sorin08d153c2015-10-30 00:04:202909// Tests that overlapping installs of the same CRX result in an error.
2910TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
Sorin Jianua8926bf2018-03-09 21:02:532911 class DataCallbackMock {
sorin08d153c2015-10-30 00:04:202912 public:
Sorin Jianu73900242018-08-17 01:11:532913 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:522914 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:532915 CrxComponent crx;
2916 crx.name = "test_jebg";
2917 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
2918 crx.version = base::Version("0.0");
2919 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:232920 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:532921 return {crx};
sorin08d153c2015-10-30 00:04:202922 }
2923 };
2924
Sorin Jianua8926bf2018-03-09 21:02:532925 class CompletionCallbackMock {
sorin08d153c2015-10-30 00:04:202926 public:
Sorin Jianua8ef73d2017-11-02 16:55:172927 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin08d153c2015-10-30 00:04:202928 static int num_call = 0;
2929 ++num_call;
2930
2931 EXPECT_LE(num_call, 2);
2932
2933 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:412934 EXPECT_EQ(Error::UPDATE_IN_PROGRESS, error);
sorin08d153c2015-10-30 00:04:202935 return;
2936 }
2937 if (num_call == 2) {
sorin7b8650522016-11-02 18:23:412938 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:172939 std::move(quit_closure).Run();
sorin08d153c2015-10-30 00:04:202940 }
2941 }
2942 };
2943
Sorin Jianua8926bf2018-03-09 21:02:532944 class MockUpdateChecker : public UpdateChecker {
sorin08d153c2015-10-30 00:04:202945 public:
dchengd0fc6aa92016-04-22 18:03:122946 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:422947 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:492948 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:532949 return std::make_unique<MockUpdateChecker>();
sorin08d153c2015-10-30 00:04:202950 }
2951
Sorin Jianuc303bf42018-09-07 16:19:332952 void CheckForUpdates(
2953 const std::string& session_id,
2954 const std::vector<std::string>& ids_to_check,
2955 const IdToComponentPtrMap& components,
2956 const base::flat_map<std::string, std::string>& additional_attributes,
2957 bool enabled_component_updates,
2958 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:222959 EXPECT_FALSE(session_id.empty());
sorin30474f02017-04-27 00:45:482960 EXPECT_TRUE(enabled_component_updates);
2961 EXPECT_EQ(1u, ids_to_check.size());
2962 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
2963 EXPECT_EQ(id, ids_to_check.front());
2964 EXPECT_EQ(1u, components.count(id));
2965
sorin7cff6e52017-05-17 16:37:232966 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:482967 result.extension_id = id;
2968 result.status = "noupdate";
2969
Sorin Jianu888ec292018-06-01 15:35:422970 ProtocolParser::Results results;
2971 results.list.push_back(result);
sorin30474f02017-04-27 00:45:482972
Sorin Jianub41a592a2018-03-02 16:30:272973 // Verify that calling Install sets |is_foreground| for the component.
Sorin Jianu888ec292018-06-01 15:35:422974 EXPECT_TRUE(components.at(id)->is_foreground());
sorin30474f02017-04-27 00:45:482975
sorin08d153c2015-10-30 00:04:202976 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:462977 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
2978 ErrorCategory::kNone, 0, 0));
sorin08d153c2015-10-30 00:04:202979 }
2980 };
2981
Sorin Jianua8926bf2018-03-09 21:02:532982 class MockCrxDownloader : public CrxDownloader {
sorin08d153c2015-10-30 00:04:202983 public:
dchengd0fc6aa92016-04-22 18:03:122984 static std::unique_ptr<CrxDownloader> Create(
sorin08d153c2015-10-30 00:04:202985 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:122986 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:532987 return std::make_unique<MockCrxDownloader>();
sorin08d153c2015-10-30 00:04:202988 }
2989
Sorin Jianua8926bf2018-03-09 21:02:532990 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin08d153c2015-10-30 00:04:202991
sorin30474f02017-04-27 00:45:482992 private:
sorin08d153c2015-10-30 00:04:202993 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
2994 };
2995
Sorin Jianua8926bf2018-03-09 21:02:532996 class MockPingManager : public MockPingManagerImpl {
sorin08d153c2015-10-30 00:04:202997 public:
Sorin Jianua8926bf2018-03-09 21:02:532998 explicit MockPingManager(scoped_refptr<Configurator> config)
2999 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543000
3001 protected:
Sorin Jianua8926bf2018-03-09 21:02:533002 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin08d153c2015-10-30 00:04:203003 };
3004
sorin30474f02017-04-27 00:45:483005 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433006 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533007 config(), base::MakeRefCounted<MockPingManager>(config()),
3008 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin08d153c2015-10-30 00:04:203009
3010 MockObserver observer;
sorin08d153c2015-10-30 00:04:203011 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3012 "jebgalgnebhfojomionfpkfelancnnkf"))
3013 .Times(1);
3014 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
3015 "jebgalgnebhfojomionfpkfelancnnkf"))
3016 .Times(1);
3017
Sorin Jianudfb12a42020-03-10 04:12:033018 std::vector<CrxUpdateItem> items1;
3019 auto receiver1 = base::MakeRefCounted<MockCrxStateChangeReceiver>();
3020 EXPECT_CALL(*receiver1, Receive(_))
3021 .WillRepeatedly(
3022 [&items1](const CrxUpdateItem& item) { items1.push_back(item); });
3023
3024 std::vector<CrxUpdateItem> items2;
3025 auto receiver2 = base::MakeRefCounted<MockCrxStateChangeReceiver>();
3026 EXPECT_CALL(*receiver2, Receive(_))
3027 .WillRepeatedly(
3028 [&items2](const CrxUpdateItem& item) { items2.push_back(item); });
3029
sorin08d153c2015-10-30 00:04:203030 update_client->AddObserver(&observer);
sorin08d153c2015-10-30 00:04:203031 update_client->Install(
3032 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:533033 base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianudfb12a42020-03-10 04:12:033034 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver1),
Sorin Jianua8926bf2018-03-09 21:02:533035 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:203036 update_client->Install(
3037 std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianua8926bf2018-03-09 21:02:533038 base::BindOnce(&DataCallbackMock::Callback),
Sorin Jianudfb12a42020-03-10 04:12:033039 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver2),
Sorin Jianua8926bf2018-03-09 21:02:533040 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin08d153c2015-10-30 00:04:203041 RunThreads();
3042
Sorin Jianudfb12a42020-03-10 04:12:033043 EXPECT_EQ(2u, items1.size());
3044 EXPECT_EQ(ComponentState::kChecking, items1[0].state);
3045 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items1[0].id.c_str());
3046 EXPECT_EQ(ComponentState::kUpToDate, items1[1].state);
3047 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items1[1].id.c_str());
3048
3049 EXPECT_TRUE(items2.empty());
3050
sorin08d153c2015-10-30 00:04:203051 update_client->RemoveObserver(&observer);
sorin08d153c2015-10-30 00:04:203052}
3053
sorin30474f02017-04-27 00:45:483054// Tests that UpdateClient::Update returns Error::INVALID_ARGUMENT when
3055// the |ids| parameter is empty.
asargente90363b2015-09-09 22:40:073056TEST_F(UpdateClientTest, EmptyIdList) {
Sorin Jianua8926bf2018-03-09 21:02:533057 class DataCallbackMock {
asargente90363b2015-09-09 22:40:073058 public:
Sorin Jianu73900242018-08-17 01:11:533059 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:523060 const std::vector<std::string>& ids) {
3061 return {};
3062 }
asargente90363b2015-09-09 22:40:073063 };
3064
Sorin Jianua8926bf2018-03-09 21:02:533065 class CompletionCallbackMock {
asargente90363b2015-09-09 22:40:073066 public:
Sorin Jianua8ef73d2017-11-02 16:55:173067 static void Callback(base::OnceClosure quit_closure, Error error) {
Sorin Jianudfb12a42020-03-10 04:12:033068 EXPECT_EQ(Error::INVALID_ARGUMENT, error);
Sorin Jianua8ef73d2017-11-02 16:55:173069 std::move(quit_closure).Run();
asargente90363b2015-09-09 22:40:073070 }
3071 };
sorin30474f02017-04-27 00:45:483072
Sorin Jianua8926bf2018-03-09 21:02:533073 class MockUpdateChecker : public UpdateChecker {
asargente90363b2015-09-09 22:40:073074 public:
dchengd0fc6aa92016-04-22 18:03:123075 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423076 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:493077 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533078 return std::make_unique<MockUpdateChecker>();
asargente90363b2015-09-09 22:40:073079 }
3080
Sorin Jianuc303bf42018-09-07 16:19:333081 void CheckForUpdates(
3082 const std::string& session_id,
3083 const std::vector<std::string>& ids_to_check,
3084 const IdToComponentPtrMap& components,
3085 const base::flat_map<std::string, std::string>& additional_attributes,
3086 bool enabled_component_updates,
3087 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223088 NOTREACHED();
3089 }
asargente90363b2015-09-09 22:40:073090 };
3091
Sorin Jianua8926bf2018-03-09 21:02:533092 class MockCrxDownloader : public CrxDownloader {
asargente90363b2015-09-09 22:40:073093 public:
dchengd0fc6aa92016-04-22 18:03:123094 static std::unique_ptr<CrxDownloader> Create(
asargente90363b2015-09-09 22:40:073095 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123096 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:533097 return std::make_unique<MockCrxDownloader>();
asargente90363b2015-09-09 22:40:073098 }
3099
Sorin Jianua8926bf2018-03-09 21:02:533100 MockCrxDownloader() : CrxDownloader(nullptr) {}
asargente90363b2015-09-09 22:40:073101
sorin30474f02017-04-27 00:45:483102 private:
asargente90363b2015-09-09 22:40:073103 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3104 };
3105
Sorin Jianua8926bf2018-03-09 21:02:533106 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu560d5022018-02-12 23:11:543107 public:
Sorin Jianua8926bf2018-03-09 21:02:533108 explicit MockPingManager(scoped_refptr<Configurator> config)
3109 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543110
3111 protected:
Sorin Jianua8926bf2018-03-09 21:02:533112 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
Sorin Jianu560d5022018-02-12 23:11:543113 };
3114
sorin30474f02017-04-27 00:45:483115 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433116 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533117 config(), base::MakeRefCounted<MockPingManager>(config()),
3118 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
asargente90363b2015-09-09 22:40:073119
sorin30474f02017-04-27 00:45:483120 const std::vector<std::string> empty_id_list;
asargente90363b2015-09-09 22:40:073121 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:033122 empty_id_list, base::BindOnce(&DataCallbackMock::Callback), {}, false,
Sorin Jianua8926bf2018-03-09 21:02:533123 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin30474f02017-04-27 00:45:483124 RunThreads();
asargente90363b2015-09-09 22:40:073125}
3126
sorin805aa03112016-01-14 23:01:313127TEST_F(UpdateClientTest, SendUninstallPing) {
Sorin Jianua8926bf2018-03-09 21:02:533128 class CompletionCallbackMock {
sorin8037ac8c2017-04-19 16:28:003129 public:
Sorin Jianua8ef73d2017-11-02 16:55:173130 static void Callback(base::OnceClosure quit_closure, Error error) {
3131 std::move(quit_closure).Run();
sorin8037ac8c2017-04-19 16:28:003132 }
3133 };
3134
Sorin Jianua8926bf2018-03-09 21:02:533135 class MockUpdateChecker : public UpdateChecker {
sorin805aa03112016-01-14 23:01:313136 public:
dchengd0fc6aa92016-04-22 18:03:123137 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423138 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:493139 PersistedData* metadata) {
sorin805aa03112016-01-14 23:01:313140 return nullptr;
3141 }
3142
Sorin Jianuc303bf42018-09-07 16:19:333143 void CheckForUpdates(
3144 const std::string& session_id,
3145 const std::vector<std::string>& ids_to_check,
3146 const IdToComponentPtrMap& components,
3147 const base::flat_map<std::string, std::string>& additional_attributes,
3148 bool enabled_component_updates,
3149 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223150 NOTREACHED();
3151 }
sorin805aa03112016-01-14 23:01:313152 };
3153
Sorin Jianua8926bf2018-03-09 21:02:533154 class MockCrxDownloader : public CrxDownloader {
sorin805aa03112016-01-14 23:01:313155 public:
dchengd0fc6aa92016-04-22 18:03:123156 static std::unique_ptr<CrxDownloader> Create(
sorin805aa03112016-01-14 23:01:313157 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123158 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
sorin805aa03112016-01-14 23:01:313159 return nullptr;
3160 }
3161
3162 private:
Sorin Jianua8926bf2018-03-09 21:02:533163 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu30881152020-03-16 14:31:193164 ~MockCrxDownloader() override = default;
sorin805aa03112016-01-14 23:01:313165
3166 void DoStartDownload(const GURL& url) override {}
3167 };
3168
Sorin Jianua8926bf2018-03-09 21:02:533169 class MockPingManager : public MockPingManagerImpl {
sorin805aa03112016-01-14 23:01:313170 public:
Sorin Jianua8926bf2018-03-09 21:02:533171 explicit MockPingManager(scoped_refptr<Configurator> config)
3172 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543173
3174 protected:
Sorin Jianua8926bf2018-03-09 21:02:533175 ~MockPingManager() override {
3176 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:483177 EXPECT_EQ(1u, ping_data.size());
3178 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
Minh X. Nguyen01d3586d2018-01-03 21:53:393179 EXPECT_EQ(base::Version("1.2.3.4"), ping_data[0].previous_version);
3180 EXPECT_EQ(base::Version("0"), ping_data[0].next_version);
sorin30474f02017-04-27 00:45:483181 EXPECT_EQ(10, ping_data[0].extra_code1);
sorin805aa03112016-01-14 23:01:313182 }
3183 };
3184
sorin30474f02017-04-27 00:45:483185 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433186 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533187 config(), base::MakeRefCounted<MockPingManager>(config()),
3188 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin805aa03112016-01-14 23:01:313189
sorin8037ac8c2017-04-19 16:28:003190 update_client->SendUninstallPing(
Minh X. Nguyen01d3586d2018-01-03 21:53:393191 "jebgalgnebhfojomionfpkfelancnnkf", base::Version("1.2.3.4"), 10,
Sorin Jianua8926bf2018-03-09 21:02:533192 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin8037ac8c2017-04-19 16:28:003193
3194 RunThreads();
sorin805aa03112016-01-14 23:01:313195}
3196
sorinfccbf2d2016-04-04 20:34:343197TEST_F(UpdateClientTest, RetryAfter) {
Sorin Jianua8926bf2018-03-09 21:02:533198 class DataCallbackMock {
sorinfccbf2d2016-04-04 20:34:343199 public:
Sorin Jianu73900242018-08-17 01:11:533200 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:523201 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:533202 CrxComponent crx;
3203 crx.name = "test_jebg";
3204 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
3205 crx.version = base::Version("0.9");
3206 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233207 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533208 return {crx};
sorinfccbf2d2016-04-04 20:34:343209 }
3210 };
3211
Sorin Jianua8926bf2018-03-09 21:02:533212 class CompletionCallbackMock {
sorinfccbf2d2016-04-04 20:34:343213 public:
Sorin Jianua8ef73d2017-11-02 16:55:173214 static void Callback(base::OnceClosure quit_closure, Error error) {
sorinfccbf2d2016-04-04 20:34:343215 static int num_call = 0;
3216 ++num_call;
3217
3218 EXPECT_LE(num_call, 4);
3219
3220 if (num_call == 1) {
sorin7b8650522016-11-02 18:23:413221 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:343222 } else if (num_call == 2) {
3223 // This request is throttled since the update engine received a
3224 // positive |retry_after_sec| value in the update check response.
sorin7b8650522016-11-02 18:23:413225 EXPECT_EQ(Error::RETRY_LATER, error);
sorinfccbf2d2016-04-04 20:34:343226 } else if (num_call == 3) {
3227 // This request is a foreground Install, which is never throttled.
3228 // The update engine received a |retry_after_sec| value of 0, which
3229 // resets the throttling.
sorin7b8650522016-11-02 18:23:413230 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:343231 } else if (num_call == 4) {
3232 // This request succeeds since there is no throttling in effect.
sorin7b8650522016-11-02 18:23:413233 EXPECT_EQ(Error::NONE, error);
sorinfccbf2d2016-04-04 20:34:343234 }
3235
Sorin Jianua8ef73d2017-11-02 16:55:173236 std::move(quit_closure).Run();
sorinfccbf2d2016-04-04 20:34:343237 }
3238 };
3239
Sorin Jianua8926bf2018-03-09 21:02:533240 class MockUpdateChecker : public UpdateChecker {
sorinfccbf2d2016-04-04 20:34:343241 public:
dchengd0fc6aa92016-04-22 18:03:123242 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423243 scoped_refptr<Configurator> config,
wafflese7dff732016-04-15 23:51:493244 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533245 return std::make_unique<MockUpdateChecker>();
sorinfccbf2d2016-04-04 20:34:343246 }
3247
Sorin Jianuc303bf42018-09-07 16:19:333248 void CheckForUpdates(
3249 const std::string& session_id,
3250 const std::vector<std::string>& ids_to_check,
3251 const IdToComponentPtrMap& components,
3252 const base::flat_map<std::string, std::string>& additional_attributes,
3253 bool enabled_component_updates,
3254 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223255 EXPECT_FALSE(session_id.empty());
3256
sorinfccbf2d2016-04-04 20:34:343257 static int num_call = 0;
3258 ++num_call;
3259
3260 EXPECT_LE(num_call, 3);
3261
3262 int retry_after_sec(0);
3263 if (num_call == 1) {
3264 // Throttle the next call.
3265 retry_after_sec = 60 * 60; // 1 hour.
3266 }
3267
sorin30474f02017-04-27 00:45:483268 EXPECT_EQ(1u, ids_to_check.size());
3269 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3270 EXPECT_EQ(id, ids_to_check.front());
3271 EXPECT_EQ(1u, components.count(id));
3272
sorin7cff6e52017-05-17 16:37:233273 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:483274 result.extension_id = id;
3275 result.status = "noupdate";
Sorin Jianu888ec292018-06-01 15:35:423276
3277 ProtocolParser::Results results;
3278 results.list.push_back(result);
sorin30474f02017-04-27 00:45:483279
sorinfccbf2d2016-04-04 20:34:343280 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:463281 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
3282 ErrorCategory::kNone, 0, retry_after_sec));
sorinfccbf2d2016-04-04 20:34:343283 }
3284 };
3285
Sorin Jianua8926bf2018-03-09 21:02:533286 class MockCrxDownloader : public CrxDownloader {
sorinfccbf2d2016-04-04 20:34:343287 public:
dchengd0fc6aa92016-04-22 18:03:123288 static std::unique_ptr<CrxDownloader> Create(
sorinfccbf2d2016-04-04 20:34:343289 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123290 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:533291 return std::make_unique<MockCrxDownloader>();
sorinfccbf2d2016-04-04 20:34:343292 }
3293
Sorin Jianua8926bf2018-03-09 21:02:533294 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorinfccbf2d2016-04-04 20:34:343295
sorin30474f02017-04-27 00:45:483296 private:
sorinfccbf2d2016-04-04 20:34:343297 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3298 };
3299
Sorin Jianua8926bf2018-03-09 21:02:533300 class MockPingManager : public MockPingManagerImpl {
sorinfccbf2d2016-04-04 20:34:343301 public:
Sorin Jianua8926bf2018-03-09 21:02:533302 explicit MockPingManager(scoped_refptr<Configurator> config)
3303 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543304
3305 protected:
Sorin Jianua8926bf2018-03-09 21:02:533306 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorinfccbf2d2016-04-04 20:34:343307 };
3308
sorin30474f02017-04-27 00:45:483309 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433310 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533311 config(), base::MakeRefCounted<MockPingManager>(config()),
3312 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorinfccbf2d2016-04-04 20:34:343313
3314 MockObserver observer;
3315
3316 InSequence seq;
3317 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3318 "jebgalgnebhfojomionfpkfelancnnkf"))
3319 .Times(1);
3320 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
3321 "jebgalgnebhfojomionfpkfelancnnkf"))
3322 .Times(1);
3323 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3324 "jebgalgnebhfojomionfpkfelancnnkf"))
3325 .Times(1);
3326 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
3327 "jebgalgnebhfojomionfpkfelancnnkf"))
3328 .Times(1);
3329 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3330 "jebgalgnebhfojomionfpkfelancnnkf"))
3331 .Times(1);
3332 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
3333 "jebgalgnebhfojomionfpkfelancnnkf"))
3334 .Times(1);
3335
3336 update_client->AddObserver(&observer);
3337
sorin30474f02017-04-27 00:45:483338 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
sorinfccbf2d2016-04-04 20:34:343339 {
3340 // The engine handles this Update call but responds with a valid
3341 // |retry_after_sec|, which causes subsequent calls to fail.
3342 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:033343 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), {},
Sorin Jianub41a592a2018-03-02 16:30:273344 false,
Sorin Jianua8926bf2018-03-09 21:02:533345 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173346 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343347 runloop.Run();
3348 }
3349
3350 {
3351 // This call will result in a completion callback invoked with
3352 // Error::ERROR_UPDATE_RETRY_LATER.
3353 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:033354 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), {},
Sorin Jianub41a592a2018-03-02 16:30:273355 false,
Sorin Jianua8926bf2018-03-09 21:02:533356 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173357 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343358 runloop.Run();
3359 }
3360
3361 {
3362 // The Install call is handled, and the throttling is reset due to
3363 // the value of |retry_after_sec| in the completion callback.
3364 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:173365 update_client->Install(std::string("jebgalgnebhfojomionfpkfelancnnkf"),
Sorin Jianudfb12a42020-03-10 04:12:033366 base::BindOnce(&DataCallbackMock::Callback), {},
Sorin Jianua8926bf2018-03-09 21:02:533367 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173368 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343369 runloop.Run();
3370 }
3371
3372 {
3373 // This call succeeds.
3374 base::RunLoop runloop;
Sorin Jianudfb12a42020-03-10 04:12:033375 update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), {},
Sorin Jianub41a592a2018-03-02 16:30:273376 false,
Sorin Jianua8926bf2018-03-09 21:02:533377 base::BindOnce(&CompletionCallbackMock::Callback,
Sorin Jianua8ef73d2017-11-02 16:55:173378 runloop.QuitClosure()));
sorinfccbf2d2016-04-04 20:34:343379 runloop.Run();
3380 }
3381
3382 update_client->RemoveObserver(&observer);
3383}
3384
sorine84ff702016-08-04 01:22:023385// Tests the update check for two CRXs scenario. The first component supports
3386// the group policy to enable updates, and has its updates disabled. The second
3387// component has an update. The server does not honor the "updatedisabled"
sorin30474f02017-04-27 00:45:483388// attribute and returns updates for both components. However, the update for
Sorin Jianu888ec292018-06-01 15:35:423389// the first component is not applied and the client responds with a
sorin30474f02017-04-27 00:45:483390// (SERVICE_ERROR, UPDATE_DISABLED)
sorine84ff702016-08-04 01:22:023391TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
Sorin Jianua8926bf2018-03-09 21:02:533392 class DataCallbackMock {
sorine84ff702016-08-04 01:22:023393 public:
Sorin Jianu73900242018-08-17 01:11:533394 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:523395 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:533396 CrxComponent crx1;
3397 crx1.name = "test_jebg";
3398 crx1.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
3399 crx1.version = base::Version("0.9");
3400 crx1.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233401 crx1.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533402 crx1.supports_group_policy_enable_component_updates = true;
sorine84ff702016-08-04 01:22:023403
Sorin Jianu73900242018-08-17 01:11:533404 CrxComponent crx2;
3405 crx2.name = "test_ihfo";
3406 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
3407 crx2.version = base::Version("0.8");
3408 crx2.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233409 crx2.crx_format_requirement = crx_file::VerifierFormat::CRX3;
sorine84ff702016-08-04 01:22:023410
Sorin Jianu73900242018-08-17 01:11:533411 return {crx1, crx2};
sorine84ff702016-08-04 01:22:023412 }
3413 };
3414
Sorin Jianua8926bf2018-03-09 21:02:533415 class CompletionCallbackMock {
sorine84ff702016-08-04 01:22:023416 public:
Sorin Jianua8ef73d2017-11-02 16:55:173417 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin7b8650522016-11-02 18:23:413418 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:173419 std::move(quit_closure).Run();
sorine84ff702016-08-04 01:22:023420 }
3421 };
3422
Sorin Jianua8926bf2018-03-09 21:02:533423 class MockUpdateChecker : public UpdateChecker {
sorine84ff702016-08-04 01:22:023424 public:
3425 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423426 scoped_refptr<Configurator> config,
sorine84ff702016-08-04 01:22:023427 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533428 return std::make_unique<MockUpdateChecker>();
sorine84ff702016-08-04 01:22:023429 }
3430
Sorin Jianuc303bf42018-09-07 16:19:333431 void CheckForUpdates(
3432 const std::string& session_id,
3433 const std::vector<std::string>& ids_to_check,
3434 const IdToComponentPtrMap& components,
3435 const base::flat_map<std::string, std::string>& additional_attributes,
3436 bool enabled_component_updates,
3437 UpdateCheckCallback update_check_callback) override {
sorine84ff702016-08-04 01:22:023438 /*
Sorin Jianua8926bf2018-03-09 21:02:533439 Mock the following response:
sorine84ff702016-08-04 01:22:023440
3441 <?xml version='1.0' encoding='UTF-8'?>
sorin39852802017-05-01 22:46:283442 <response protocol='3.1'>
sorine84ff702016-08-04 01:22:023443 <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
3444 <updatecheck status='ok'>
3445 <urls>
3446 <url codebase='http://localhost/download/'/>
3447 </urls>
3448 <manifest version='1.0' prodversionmin='11.0.1.0'>
3449 <packages>
3450 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:233451 hash_sha256='7ab32f071cd9b5ef8e0d7913be161f532d98b3e9f
3452 a284a7cd8059c3409ce0498'/>
sorine84ff702016-08-04 01:22:023453 </packages>
3454 </manifest>
3455 </updatecheck>
3456 </app>
3457 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
3458 <updatecheck status='ok'>
3459 <urls>
3460 <url codebase='http://localhost/download/'/>
3461 </urls>
3462 <manifest version='1.0' prodversionmin='11.0.1.0'>
3463 <packages>
3464 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
Joshua Pawlickiafaa2922019-09-03 18:50:233465 hash_sha256='8f5aa190311237cae00675af87ff457f278cd1a05
3466 895470ac5d46647d4a3c2ea'/>
sorine84ff702016-08-04 01:22:023467 </packages>
3468 </manifest>
3469 </updatecheck>
3470 </app>
3471 </response>
3472 */
sorin590921d2016-08-11 23:48:363473
3474 // UpdateClient reads the state of |enabled_component_updates| from the
3475 // configurator instance, persists its value in the corresponding
3476 // update context, and propagates it down to each of the update actions,
3477 // and further down to the UpdateChecker instance.
Sorin Jianud69d4372018-02-07 19:44:223478 EXPECT_FALSE(session_id.empty());
sorin590921d2016-08-11 23:48:363479 EXPECT_FALSE(enabled_component_updates);
sorin30474f02017-04-27 00:45:483480 EXPECT_EQ(2u, ids_to_check.size());
sorine84ff702016-08-04 01:22:023481
Sorin Jianu888ec292018-06-01 15:35:423482 ProtocolParser::Results results;
sorin30474f02017-04-27 00:45:483483 {
3484 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3485 EXPECT_EQ(id, ids_to_check[0]);
3486 EXPECT_EQ(1u, components.count(id));
sorine84ff702016-08-04 01:22:023487
sorin7cff6e52017-05-17 16:37:233488 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:483489 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
3490 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:233491 "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
sorine84ff702016-08-04 01:22:023492
sorin7cff6e52017-05-17 16:37:233493 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:483494 result.extension_id = id;
3495 result.status = "ok";
3496 result.crx_urls.push_back(GURL("http://localhost/download/"));
3497 result.manifest.version = "1.0";
3498 result.manifest.browser_min_version = "11.0.1.0";
3499 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:423500 results.list.push_back(result);
sorin30474f02017-04-27 00:45:483501 }
3502
3503 {
3504 const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
3505 EXPECT_EQ(id, ids_to_check[1]);
3506 EXPECT_EQ(1u, components.count(id));
3507
sorin7cff6e52017-05-17 16:37:233508 ProtocolParser::Result::Manifest::Package package;
sorin30474f02017-04-27 00:45:483509 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
3510 package.hash_sha256 =
Joshua Pawlickiafaa2922019-09-03 18:50:233511 "8f5aa190311237cae00675af87ff457f278cd1a05895470ac5d46647d4a3c2ea";
sorin30474f02017-04-27 00:45:483512
sorin7cff6e52017-05-17 16:37:233513 ProtocolParser::Result result;
sorin30474f02017-04-27 00:45:483514 result.extension_id = id;
3515 result.status = "ok";
3516 result.crx_urls.push_back(GURL("http://localhost/download/"));
3517 result.manifest.version = "1.0";
3518 result.manifest.browser_min_version = "11.0.1.0";
3519 result.manifest.packages.push_back(package);
Sorin Jianu888ec292018-06-01 15:35:423520 results.list.push_back(result);
sorin30474f02017-04-27 00:45:483521 }
sorine84ff702016-08-04 01:22:023522
3523 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:463524 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
3525 ErrorCategory::kNone, 0, 0));
sorine84ff702016-08-04 01:22:023526 }
3527 };
3528
Sorin Jianua8926bf2018-03-09 21:02:533529 class MockCrxDownloader : public CrxDownloader {
sorine84ff702016-08-04 01:22:023530 public:
3531 static std::unique_ptr<CrxDownloader> Create(
3532 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123533 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:533534 return std::make_unique<MockCrxDownloader>();
sorine84ff702016-08-04 01:22:023535 }
3536
Sorin Jianua8926bf2018-03-09 21:02:533537 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorine84ff702016-08-04 01:22:023538
sorin30474f02017-04-27 00:45:483539 private:
sorine84ff702016-08-04 01:22:023540 void DoStartDownload(const GURL& url) override {
3541 DownloadMetrics download_metrics;
3542 FilePath path;
3543 Result result;
3544 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
3545 download_metrics.url = url;
3546 download_metrics.downloader = DownloadMetrics::kNone;
3547 download_metrics.error = 0;
3548 download_metrics.downloaded_bytes = 53638;
3549 download_metrics.total_bytes = 53638;
3550 download_metrics.download_time_ms = 2000;
3551
3552 EXPECT_TRUE(MakeTestFile(
3553 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
3554
3555 result.error = 0;
3556 result.response = path;
sorine84ff702016-08-04 01:22:023557 } else {
3558 NOTREACHED();
3559 }
3560
3561 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533562 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress,
Antonio Gomes31237fb2018-08-27 19:11:033563 base::Unretained(this)));
sorine84ff702016-08-04 01:22:023564
3565 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:533566 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:583567 base::Unretained(this), true, result,
3568 download_metrics));
sorine84ff702016-08-04 01:22:023569 }
3570 };
3571
Sorin Jianua8926bf2018-03-09 21:02:533572 class MockPingManager : public MockPingManagerImpl {
sorine84ff702016-08-04 01:22:023573 public:
Sorin Jianua8926bf2018-03-09 21:02:533574 explicit MockPingManager(scoped_refptr<Configurator> config)
3575 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543576
3577 protected:
Sorin Jianua8926bf2018-03-09 21:02:533578 ~MockPingManager() override {
3579 const auto ping_data = MockPingManagerImpl::ping_data();
sorin30474f02017-04-27 00:45:483580 EXPECT_EQ(2u, ping_data.size());
3581 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
3582 EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
3583 EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:103584 EXPECT_EQ(4, static_cast<int>(ping_data[0].error_category));
sorin30474f02017-04-27 00:45:483585 EXPECT_EQ(2, ping_data[0].error_code);
3586 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
3587 EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
3588 EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
Minh X. Nguyena4640cb2018-05-23 21:29:103589 EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
sorin30474f02017-04-27 00:45:483590 EXPECT_EQ(0, ping_data[1].error_code);
sorine84ff702016-08-04 01:22:023591 }
3592 };
3593
3594 // Disables updates for the components declaring support for the group policy.
3595 config()->SetEnabledComponentUpdates(false);
sorin30474f02017-04-27 00:45:483596 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433597 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533598 config(), base::MakeRefCounted<MockPingManager>(config()),
3599 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorine84ff702016-08-04 01:22:023600
3601 MockObserver observer;
3602 {
3603 InSequence seq;
3604 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3605 "jebgalgnebhfojomionfpkfelancnnkf"))
3606 .Times(1);
3607 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3608 "jebgalgnebhfojomionfpkfelancnnkf"))
3609 .Times(1);
Sorin Jianucbb10e12018-01-23 18:01:443610 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
sorine84ff702016-08-04 01:22:023611 "jebgalgnebhfojomionfpkfelancnnkf"))
3612 .Times(1);
3613 }
3614 {
3615 InSequence seq;
3616 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3617 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3618 .Times(1);
3619 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
3620 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3621 .Times(1);
sorine84ff702016-08-04 01:22:023622 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
3623 "ihfokbkgjpifnbbojhneepfflplebdkc"))
sorin30474f02017-04-27 00:45:483624 .Times(AtLeast(1));
sorine84ff702016-08-04 01:22:023625 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
3626 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3627 .Times(1);
3628 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
3629 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3630 .Times(1);
3631 }
3632
Sorin Jianudfb12a42020-03-10 04:12:033633 std::vector<CrxUpdateItem> items;
3634 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
3635 EXPECT_CALL(*receiver, Receive(_))
3636 .WillRepeatedly(
3637 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorine84ff702016-08-04 01:22:023638
Sorin Jianudfb12a42020-03-10 04:12:033639 update_client->AddObserver(&observer);
sorin30474f02017-04-27 00:45:483640 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
3641 "ihfokbkgjpifnbbojhneepfflplebdkc"};
sorine84ff702016-08-04 01:22:023642 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:033643 ids, base::BindOnce(&DataCallbackMock::Callback),
3644 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
3645 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorine84ff702016-08-04 01:22:023646 RunThreads();
3647
Sorin Jianudfb12a42020-03-10 04:12:033648 EXPECT_EQ(9u, items.size());
3649 EXPECT_EQ(ComponentState::kChecking, items[0].state);
3650 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
3651 EXPECT_EQ(ComponentState::kChecking, items[1].state);
3652 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[1].id.c_str());
3653 EXPECT_EQ(ComponentState::kCanUpdate, items[2].state);
3654 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[2].id.c_str());
3655 EXPECT_EQ(ComponentState::kUpdateError, items[3].state);
3656 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[3].id.c_str());
3657 EXPECT_EQ(ComponentState::kCanUpdate, items[4].state);
3658 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[4].id.c_str());
3659 EXPECT_EQ(ComponentState::kDownloading, items[5].state);
3660 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[5].id.c_str());
3661 EXPECT_EQ(ComponentState::kDownloading, items[6].state);
3662 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[6].id.c_str());
3663 EXPECT_EQ(ComponentState::kUpdating, items[7].state);
3664 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[7].id.c_str());
3665 EXPECT_EQ(ComponentState::kUpdated, items[8].state);
3666 EXPECT_STREQ("ihfokbkgjpifnbbojhneepfflplebdkc", items[8].id.c_str());
3667
sorine84ff702016-08-04 01:22:023668 update_client->RemoveObserver(&observer);
3669}
3670
sorin03ec5b72017-05-01 23:14:243671// Tests the scenario where the update check fails.
3672TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
Sorin Jianua8926bf2018-03-09 21:02:533673 class DataCallbackMock {
sorin03ec5b72017-05-01 23:14:243674 public:
Sorin Jianu73900242018-08-17 01:11:533675 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianu7c22795b2018-04-26 22:16:523676 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:533677 CrxComponent crx;
3678 crx.name = "test_jebg";
3679 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
3680 crx.version = base::Version("0.9");
3681 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233682 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533683 return {crx};
sorin03ec5b72017-05-01 23:14:243684 }
3685 };
3686
Sorin Jianua8926bf2018-03-09 21:02:533687 class CompletionCallbackMock {
sorin03ec5b72017-05-01 23:14:243688 public:
Sorin Jianua8ef73d2017-11-02 16:55:173689 static void Callback(base::OnceClosure quit_closure, Error error) {
sorin03ec5b72017-05-01 23:14:243690 EXPECT_EQ(Error::UPDATE_CHECK_ERROR, error);
Sorin Jianua8ef73d2017-11-02 16:55:173691 std::move(quit_closure).Run();
sorin03ec5b72017-05-01 23:14:243692 }
3693 };
3694
Sorin Jianua8926bf2018-03-09 21:02:533695 class MockUpdateChecker : public UpdateChecker {
sorin03ec5b72017-05-01 23:14:243696 public:
3697 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:423698 scoped_refptr<Configurator> config,
sorin03ec5b72017-05-01 23:14:243699 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:533700 return std::make_unique<MockUpdateChecker>();
sorin03ec5b72017-05-01 23:14:243701 }
3702
Sorin Jianuc303bf42018-09-07 16:19:333703 void CheckForUpdates(
3704 const std::string& session_id,
3705 const std::vector<std::string>& ids_to_check,
3706 const IdToComponentPtrMap& components,
3707 const base::flat_map<std::string, std::string>& additional_attributes,
3708 bool enabled_component_updates,
3709 UpdateCheckCallback update_check_callback) override {
Sorin Jianud69d4372018-02-07 19:44:223710 EXPECT_FALSE(session_id.empty());
sorin03ec5b72017-05-01 23:14:243711 EXPECT_TRUE(enabled_component_updates);
3712 EXPECT_EQ(1u, ids_to_check.size());
3713 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
3714 EXPECT_EQ(id, ids_to_check.front());
3715 EXPECT_EQ(1u, components.count(id));
sorin03ec5b72017-05-01 23:14:243716 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianu888ec292018-06-01 15:35:423717 FROM_HERE,
3718 base::BindOnce(std::move(update_check_callback), base::nullopt,
3719 ErrorCategory::kUpdateCheck, -1, 0));
sorin03ec5b72017-05-01 23:14:243720 }
3721 };
3722
Sorin Jianua8926bf2018-03-09 21:02:533723 class MockCrxDownloader : public CrxDownloader {
sorin03ec5b72017-05-01 23:14:243724 public:
3725 static std::unique_ptr<CrxDownloader> Create(
3726 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123727 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:533728 return std::make_unique<MockCrxDownloader>();
sorin03ec5b72017-05-01 23:14:243729 }
3730
Sorin Jianua8926bf2018-03-09 21:02:533731 MockCrxDownloader() : CrxDownloader(nullptr) {}
sorin03ec5b72017-05-01 23:14:243732
3733 private:
3734 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3735 };
3736
Sorin Jianua8926bf2018-03-09 21:02:533737 class MockPingManager : public MockPingManagerImpl {
sorin03ec5b72017-05-01 23:14:243738 public:
Sorin Jianua8926bf2018-03-09 21:02:533739 explicit MockPingManager(scoped_refptr<Configurator> config)
3740 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:543741
3742 protected:
Sorin Jianua8926bf2018-03-09 21:02:533743 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
sorin03ec5b72017-05-01 23:14:243744 };
3745
3746 scoped_refptr<UpdateClient> update_client =
Taiju Tsuiki36c517d2017-05-18 06:45:433747 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:533748 config(), base::MakeRefCounted<MockPingManager>(config()),
3749 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
sorin03ec5b72017-05-01 23:14:243750
3751 MockObserver observer;
Sorin Jianudfb12a42020-03-10 04:12:033752 {
3753 InSequence seq;
3754 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3755 "jebgalgnebhfojomionfpkfelancnnkf"))
3756 .Times(1);
3757 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3758 "jebgalgnebhfojomionfpkfelancnnkf"))
3759 .Times(1)
3760 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3761 CrxUpdateItem item;
3762 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
3763 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3764 EXPECT_EQ(5, static_cast<int>(item.error_category));
3765 EXPECT_EQ(-1, item.error_code);
3766 EXPECT_EQ(0, item.extra_code1);
3767 }));
3768 }
3769
3770 std::vector<CrxUpdateItem> items;
3771 auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
3772 EXPECT_CALL(*receiver, Receive(_))
3773 .WillRepeatedly(
3774 [&items](const CrxUpdateItem& item) { items.push_back(item); });
sorin03ec5b72017-05-01 23:14:243775
3776 update_client->AddObserver(&observer);
sorin03ec5b72017-05-01 23:14:243777 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
3778 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:033779 ids, base::BindOnce(&DataCallbackMock::Callback),
3780 base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver),
3781 false, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
sorin03ec5b72017-05-01 23:14:243782 RunThreads();
3783
Sorin Jianudfb12a42020-03-10 04:12:033784 EXPECT_EQ(2u, items.size());
3785 EXPECT_EQ(ComponentState::kChecking, items[0].state);
3786 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[0].id.c_str());
3787 EXPECT_EQ(ComponentState::kUpdateError, items[1].state);
3788 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[1].id.c_str());
3789
sorin03ec5b72017-05-01 23:14:243790 update_client->RemoveObserver(&observer);
3791}
3792
Sorin Jianuaa4165532018-06-08 19:46:463793// Tests the scenario where the server responds with different values for
3794// application status.
3795TEST_F(UpdateClientTest, OneCrxErrorUnknownApp) {
3796 class DataCallbackMock {
3797 public:
Sorin Jianu73900242018-08-17 01:11:533798 static std::vector<base::Optional<CrxComponent>> Callback(
Sorin Jianuaa4165532018-06-08 19:46:463799 const std::vector<std::string>& ids) {
Sorin Jianu73900242018-08-17 01:11:533800 std::vector<base::Optional<CrxComponent>> component;
3801 {
3802 CrxComponent crx;
3803 crx.name = "test_jebg";
3804 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
3805 crx.version = base::Version("0.9");
3806 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233807 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533808 component.push_back(crx);
3809 }
3810 {
3811 CrxComponent crx;
3812 crx.name = "test_abag";
3813 crx.pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
3814 crx.version = base::Version("0.1");
3815 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233816 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533817 component.push_back(crx);
3818 }
3819 {
3820 CrxComponent crx;
3821 crx.name = "test_ihfo";
3822 crx.pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
3823 crx.version = base::Version("0.2");
3824 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233825 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533826 component.push_back(crx);
3827 }
3828 {
3829 CrxComponent crx;
3830 crx.name = "test_gjpm";
3831 crx.pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
3832 crx.version = base::Version("0.3");
3833 crx.installer = base::MakeRefCounted<TestInstaller>();
Joshua Pawlickiafaa2922019-09-03 18:50:233834 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:533835 component.push_back(crx);
3836 }
Sorin Jianuaa4165532018-06-08 19:46:463837 return component;
3838 }
3839 };
3840
3841 class CompletionCallbackMock {
3842 public:
3843 static void Callback(base::OnceClosure quit_closure, Error error) {
3844 EXPECT_EQ(Error::NONE, error);
3845 std::move(quit_closure).Run();
3846 }
3847 };
3848
3849 class MockUpdateChecker : public UpdateChecker {
3850 public:
3851 static std::unique_ptr<UpdateChecker> Create(
3852 scoped_refptr<Configurator> config,
3853 PersistedData* metadata) {
3854 return std::make_unique<MockUpdateChecker>();
3855 }
3856
Sorin Jianuc303bf42018-09-07 16:19:333857 void CheckForUpdates(
3858 const std::string& session_id,
3859 const std::vector<std::string>& ids_to_check,
3860 const IdToComponentPtrMap& components,
3861 const base::flat_map<std::string, std::string>& additional_attributes,
3862 bool enabled_component_updates,
3863 UpdateCheckCallback update_check_callback) override {
Sorin Jianuaa4165532018-06-08 19:46:463864 EXPECT_FALSE(session_id.empty());
3865 EXPECT_TRUE(enabled_component_updates);
3866 EXPECT_EQ(4u, ids_to_check.size());
3867
3868 const std::string update_response =
Joshua Pawlicki8ac39322019-04-04 21:22:463869 ")]}'"
3870 R"({"response": {)"
3871 R"( "protocol": "3.1",)"
3872 R"( "app": [)"
3873 R"({"appid": "jebgalgnebhfojomionfpkfelancnnkf",)"
3874 R"( "status": "error-unknownApplication"},)"
3875 R"({"appid": "abagagagagagagagagagagagagagagag",)"
3876 R"( "status": "restricted"},)"
3877 R"({"appid": "ihfokbkgjpifnbbojhneepfflplebdkc",)"
3878 R"( "status": "error-invalidAppId"},)"
3879 R"({"appid": "gjpmebpgbhcamgdgjcmnjfhggjpgcimm",)"
3880 R"( "status": "error-foobarApp"})"
3881 R"(]}})";
Sorin Jianuaa4165532018-06-08 19:46:463882
Joshua Pawlicki8ac39322019-04-04 21:22:463883 const auto parser = ProtocolHandlerFactoryJSON().CreateParser();
Sorin Jianu039032b2018-10-12 21:48:133884 EXPECT_TRUE(parser->Parse(update_response));
Sorin Jianuaa4165532018-06-08 19:46:463885
3886 base::ThreadTaskRunnerHandle::Get()->PostTask(
3887 FROM_HERE,
Sorin Jianu039032b2018-10-12 21:48:133888 base::BindOnce(std::move(update_check_callback), parser->results(),
Sorin Jianuaa4165532018-06-08 19:46:463889 ErrorCategory::kNone, 0, 0));
3890 }
3891 };
3892
3893 class MockCrxDownloader : public CrxDownloader {
3894 public:
3895 static std::unique_ptr<CrxDownloader> Create(
3896 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:123897 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianuaa4165532018-06-08 19:46:463898 return std::make_unique<MockCrxDownloader>();
3899 }
3900
3901 MockCrxDownloader() : CrxDownloader(nullptr) {}
3902
3903 private:
3904 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
3905 };
3906
3907 class MockPingManager : public MockPingManagerImpl {
3908 public:
3909 explicit MockPingManager(scoped_refptr<Configurator> config)
3910 : MockPingManagerImpl(config) {}
3911
3912 protected:
3913 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
3914 };
3915
3916 scoped_refptr<UpdateClient> update_client =
3917 base::MakeRefCounted<UpdateClientImpl>(
3918 config(), base::MakeRefCounted<MockPingManager>(config()),
3919 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
3920
3921 MockObserver observer;
3922 {
3923 InSequence seq;
3924 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3925 "jebgalgnebhfojomionfpkfelancnnkf"))
3926 .Times(1);
3927 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3928 "jebgalgnebhfojomionfpkfelancnnkf"))
3929 .Times(1)
3930 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3931 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:533932 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianuaa4165532018-06-08 19:46:463933 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3934 EXPECT_EQ(5, static_cast<int>(item.error_category));
3935 EXPECT_EQ(-10006, item.error_code); // UNKNOWN_APPPLICATION.
3936 EXPECT_EQ(0, item.extra_code1);
3937 }));
3938 }
3939 {
3940 InSequence seq;
3941 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3942 "abagagagagagagagagagagagagagagag"))
3943 .Times(1);
3944 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3945 "abagagagagagagagagagagagagagagag"))
3946 .Times(1)
3947 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3948 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:533949 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianuaa4165532018-06-08 19:46:463950 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3951 EXPECT_EQ(5, static_cast<int>(item.error_category));
3952 EXPECT_EQ(-10007, item.error_code); // RESTRICTED_APPLICATION.
3953 EXPECT_EQ(0, item.extra_code1);
3954 }));
3955 }
3956 {
3957 InSequence seq;
3958 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3959 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3960 .Times(1);
3961 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3962 "ihfokbkgjpifnbbojhneepfflplebdkc"))
3963 .Times(1)
3964 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3965 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:533966 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianuaa4165532018-06-08 19:46:463967 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3968 EXPECT_EQ(5, static_cast<int>(item.error_category));
3969 EXPECT_EQ(-10008, item.error_code); // INVALID_APPID.
3970 EXPECT_EQ(0, item.extra_code1);
3971 }));
3972 }
3973 {
3974 InSequence seq;
3975 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
3976 "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"))
3977 .Times(1);
3978 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
3979 "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"))
3980 .Times(1)
3981 .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
3982 CrxUpdateItem item;
Sorin Jianu73900242018-08-17 01:11:533983 EXPECT_TRUE(update_client->GetCrxUpdateState(id, &item));
Sorin Jianuaa4165532018-06-08 19:46:463984 EXPECT_EQ(ComponentState::kUpdateError, item.state);
3985 EXPECT_EQ(5, static_cast<int>(item.error_category));
3986 EXPECT_EQ(-10004, item.error_code); // UPDATE_RESPONSE_NOT_FOUND.
3987 EXPECT_EQ(0, item.extra_code1);
3988 }));
3989 }
3990
3991 update_client->AddObserver(&observer);
3992
3993 const std::vector<std::string> ids = {
3994 "jebgalgnebhfojomionfpkfelancnnkf", "abagagagagagagagagagagagagagagag",
3995 "ihfokbkgjpifnbbojhneepfflplebdkc", "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
3996 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:033997 ids, base::BindOnce(&DataCallbackMock::Callback), {}, true,
Sorin Jianuaa4165532018-06-08 19:46:463998 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
3999
4000 RunThreads();
4001
4002 update_client->RemoveObserver(&observer);
4003}
4004
Sorin Jianu4ab7c292017-06-15 18:40:214005// Tests that a run action in invoked in the CRX install scenario.
4006TEST_F(UpdateClientTest, ActionRun_Install) {
Sorin Jianua8926bf2018-03-09 21:02:534007 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:214008 public:
4009 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:424010 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:214011 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:534012 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:214013 }
4014
Sorin Jianuc303bf42018-09-07 16:19:334015 void CheckForUpdates(
4016 const std::string& session_id,
4017 const std::vector<std::string>& ids_to_check,
4018 const IdToComponentPtrMap& components,
4019 const base::flat_map<std::string, std::string>& additional_attributes,
4020 bool enabled_component_updates,
4021 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:214022 /*
Sorin Jianua8926bf2018-03-09 21:02:534023 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:214024
4025 <?xml version='1.0' encoding='UTF-8'?>
4026 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:564027 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:214028 <updatecheck status='ok'>
4029 <urls>
4030 <url codebase='http://localhost/download/'/>
4031 </urls>
4032 <manifest version='1.0' prodversionmin='11.0.1.0'>
4033 <packages>
4034 <package name='runaction_test_win.crx3'
Sorin Jianue5bfb5b2017-06-20 21:30:564035 hash_sha256='89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea'/>
Sorin Jianu4ab7c292017-06-15 18:40:214036 </packages>
4037 </manifest>
4038 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:564039 <action run='ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:214040 </actions>"
4041 </updatecheck>
4042 </app>
4043 </response>
4044 */
Sorin Jianud69d4372018-02-07 19:44:224045 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:214046 EXPECT_TRUE(enabled_component_updates);
4047 EXPECT_EQ(1u, ids_to_check.size());
4048
Sorin Jianue5bfb5b2017-06-20 21:30:564049 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:214050 EXPECT_EQ(id, ids_to_check[0]);
4051 EXPECT_EQ(1u, components.count(id));
4052
4053 ProtocolParser::Result::Manifest::Package package;
4054 package.name = "runaction_test_win.crx3";
4055 package.hash_sha256 =
Sorin Jianue5bfb5b2017-06-20 21:30:564056 "89290a0d2ff21ca5b45e109c6cc859ab5fe294e19c102d54acd321429c372cea";
Sorin Jianu4ab7c292017-06-15 18:40:214057
4058 ProtocolParser::Result result;
4059 result.extension_id = id;
4060 result.status = "ok";
4061 result.crx_urls.push_back(GURL("http://localhost/download/"));
4062 result.manifest.version = "1.0";
4063 result.manifest.browser_min_version = "11.0.1.0";
4064 result.manifest.packages.push_back(package);
Sorin Jianue5bfb5b2017-06-20 21:30:564065 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:214066
Sorin Jianu888ec292018-06-01 15:35:424067 ProtocolParser::Results results;
4068 results.list.push_back(result);
Sorin Jianu4ab7c292017-06-15 18:40:214069
4070 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:464071 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
4072 ErrorCategory::kNone, 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:214073 }
4074 };
4075
Sorin Jianua8926bf2018-03-09 21:02:534076 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:214077 public:
4078 static std::unique_ptr<CrxDownloader> Create(
4079 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:124080 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:534081 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:214082 }
4083
Sorin Jianua8926bf2018-03-09 21:02:534084 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:214085
4086 private:
4087 void DoStartDownload(const GURL& url) override {
4088 DownloadMetrics download_metrics;
4089 FilePath path;
4090 Result result;
4091 if (url.path() == "/download/runaction_test_win.crx3") {
4092 download_metrics.url = url;
4093 download_metrics.downloader = DownloadMetrics::kNone;
4094 download_metrics.error = 0;
4095 download_metrics.downloaded_bytes = 1843;
4096 download_metrics.total_bytes = 1843;
4097 download_metrics.download_time_ms = 1000;
4098
4099 EXPECT_TRUE(
4100 MakeTestFile(TestFilePath("runaction_test_win.crx3"), &path));
4101
4102 result.error = 0;
4103 result.response = path;
Sorin Jianu4ab7c292017-06-15 18:40:214104 } else {
4105 NOTREACHED();
4106 }
4107
4108 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8926bf2018-03-09 21:02:534109 FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete,
Sorin Jianuebd652462017-07-23 02:00:584110 base::Unretained(this), true, result,
4111 download_metrics));
Sorin Jianu4ab7c292017-06-15 18:40:214112 }
4113 };
4114
Sorin Jianua8926bf2018-03-09 21:02:534115 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:214116 public:
Sorin Jianua8926bf2018-03-09 21:02:534117 explicit MockPingManager(scoped_refptr<Configurator> config)
4118 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:544119
4120 protected:
Sorin Jianua8926bf2018-03-09 21:02:534121 ~MockPingManager() override {
Sorin Jianu039032b2018-10-12 21:48:134122 EXPECT_EQ(3u, events().size());
4123
4124 /*
4125 "<event eventtype="14" eventresult="1" downloader="unknown" "
4126 "url="http://localhost/download/runaction_test_win.crx3"
Sorin Jianu55587d32018-11-14 21:43:274127 "downloaded=1843 "
4128 "total=1843 download_time_ms="1000" previousversion="0.0" "
Sorin Jianu039032b2018-10-12 21:48:134129 "nextversion="1.0"/>"
4130 */
4131 const auto& event0 = events()[0];
4132 EXPECT_EQ(14, event0.FindKey("eventtype")->GetInt());
4133 EXPECT_EQ(1, event0.FindKey("eventresult")->GetInt());
4134 EXPECT_EQ("unknown", event0.FindKey("downloader")->GetString());
4135 EXPECT_EQ("http://localhost/download/runaction_test_win.crx3",
4136 event0.FindKey("url")->GetString());
Sorin Jianu55587d32018-11-14 21:43:274137 EXPECT_EQ(1843, event0.FindKey("downloaded")->GetDouble());
4138 EXPECT_EQ(1843, event0.FindKey("total")->GetDouble());
4139 EXPECT_EQ(1000, event0.FindKey("download_time_ms")->GetDouble());
Sorin Jianu039032b2018-10-12 21:48:134140 EXPECT_EQ("0.0", event0.FindKey("previousversion")->GetString());
4141 EXPECT_EQ("1.0", event0.FindKey("nextversion")->GetString());
4142
4143 // "<event eventtype="42" eventresult="1" errorcode="1877345072"/>"
4144 const auto& event1 = events()[1];
4145 EXPECT_EQ(42, event1.FindKey("eventtype")->GetInt());
4146 EXPECT_EQ(1, event1.FindKey("eventresult")->GetInt());
4147 EXPECT_EQ(1877345072, event1.FindKey("errorcode")->GetInt());
4148
4149 // "<event eventtype=\"3\" eventresult=\"1\" previousversion=\"0.0\" "
4150 // "nextversion=\"1.0\"/>",
4151 const auto& event2 = events()[2];
4152 EXPECT_EQ(3, event2.FindKey("eventtype")->GetInt());
4153 EXPECT_EQ(1, event1.FindKey("eventresult")->GetInt());
4154 EXPECT_EQ("0.0", event0.FindKey("previousversion")->GetString());
4155 EXPECT_EQ("1.0", event0.FindKey("nextversion")->GetString());
Sorin Jianu4ab7c292017-06-15 18:40:214156 }
4157 };
4158
4159 scoped_refptr<UpdateClient> update_client =
4160 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:534161 config(), base::MakeRefCounted<MockPingManager>(config()),
4162 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:214163
Sorin Jianu4ab7c292017-06-15 18:40:214164 update_client->Install(
Sorin Jianue5bfb5b2017-06-20 21:30:564165 std::string("gjpmebpgbhcamgdgjcmnjfhggjpgcimm"),
Sorin Jianu7c22795b2018-04-26 22:16:524166 base::BindOnce([](const std::vector<std::string>& ids) {
Sorin Jianu2fe49a02019-11-25 19:15:564167 auto action_handler = base::MakeRefCounted<MockActionHandler>();
4168 EXPECT_CALL(*action_handler, Handle(_, _, _))
4169 .WillOnce([](const base::FilePath& action,
4170 const std::string& session_id,
4171 ActionHandler::Callback callback) {
4172 EXPECT_EQ("ChromeRecovery.crx3",
4173 action.BaseName().MaybeAsASCII());
4174 EXPECT_TRUE(!session_id.empty());
4175 std::move(callback).Run(true, 1877345072, 0);
4176 });
4177
Sorin Jianu73900242018-08-17 01:11:534178 CrxComponent crx;
4179 crx.name = "test_niea";
4180 crx.pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
4181 crx.version = base::Version("0.0");
4182 crx.installer = base::MakeRefCounted<VersionedTestInstaller>();
Sorin Jianu2fe49a02019-11-25 19:15:564183 crx.action_handler = action_handler;
Joshua Pawlickiafaa2922019-09-03 18:50:234184 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:534185 return std::vector<base::Optional<CrxComponent>>{crx};
Sorin Jianu4ab7c292017-06-15 18:40:214186 }),
Sorin Jianudfb12a42020-03-10 04:12:034187 {},
Sorin Jianua8ef73d2017-11-02 16:55:174188 base::BindOnce(
4189 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:214190 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:174191 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:214192 },
4193 quit_closure()));
4194
4195 RunThreads();
4196}
4197
4198// Tests that a run action is invoked in an update scenario when there was
4199// no update.
4200TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
Sorin Jianua8926bf2018-03-09 21:02:534201 class MockUpdateChecker : public UpdateChecker {
Sorin Jianu4ab7c292017-06-15 18:40:214202 public:
4203 static std::unique_ptr<UpdateChecker> Create(
Sorin Jianu49126332018-02-13 17:07:424204 scoped_refptr<Configurator> config,
Sorin Jianu4ab7c292017-06-15 18:40:214205 PersistedData* metadata) {
Sorin Jianua8926bf2018-03-09 21:02:534206 return std::make_unique<MockUpdateChecker>();
Sorin Jianu4ab7c292017-06-15 18:40:214207 }
4208
Sorin Jianuc303bf42018-09-07 16:19:334209 void CheckForUpdates(
4210 const std::string& session_id,
4211 const std::vector<std::string>& ids_to_check,
4212 const IdToComponentPtrMap& components,
4213 const base::flat_map<std::string, std::string>& additional_attributes,
4214 bool enabled_component_updates,
4215 UpdateCheckCallback update_check_callback) override {
Sorin Jianu4ab7c292017-06-15 18:40:214216 /*
Sorin Jianua8926bf2018-03-09 21:02:534217 Mock the following response:
Sorin Jianu4ab7c292017-06-15 18:40:214218
4219 <?xml version='1.0' encoding='UTF-8'?>
4220 <response protocol='3.1'>
Sorin Jianue5bfb5b2017-06-20 21:30:564221 <app appid='gjpmebpgbhcamgdgjcmnjfhggjpgcimm'>
Sorin Jianu4ab7c292017-06-15 18:40:214222 <updatecheck status='noupdate'>
4223 <actions>"
Sorin Jianue5bfb5b2017-06-20 21:30:564224 <action run=ChromeRecovery.crx3'/>"
Sorin Jianu4ab7c292017-06-15 18:40:214225 </actions>"
4226 </updatecheck>
4227 </app>
4228 </response>
4229 */
Sorin Jianud69d4372018-02-07 19:44:224230 EXPECT_FALSE(session_id.empty());
Sorin Jianu4ab7c292017-06-15 18:40:214231 EXPECT_EQ(1u, ids_to_check.size());
Sorin Jianue5bfb5b2017-06-20 21:30:564232 const std::string id = "gjpmebpgbhcamgdgjcmnjfhggjpgcimm";
Sorin Jianu4ab7c292017-06-15 18:40:214233 EXPECT_EQ(id, ids_to_check[0]);
4234 EXPECT_EQ(1u, components.count(id));
4235
Sorin Jianu4ab7c292017-06-15 18:40:214236 ProtocolParser::Result result;
4237 result.extension_id = id;
4238 result.status = "noupdate";
Sorin Jianue5bfb5b2017-06-20 21:30:564239 result.action_run = "ChromeRecovery.crx3";
Sorin Jianu4ab7c292017-06-15 18:40:214240
Sorin Jianu888ec292018-06-01 15:35:424241 ProtocolParser::Results results;
4242 results.list.push_back(result);
Sorin Jianu4ab7c292017-06-15 18:40:214243
4244 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuaa4165532018-06-08 19:46:464245 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
4246 ErrorCategory::kNone, 0, 0));
Sorin Jianu4ab7c292017-06-15 18:40:214247 }
4248 };
4249
Sorin Jianua8926bf2018-03-09 21:02:534250 class MockCrxDownloader : public CrxDownloader {
Sorin Jianu4ab7c292017-06-15 18:40:214251 public:
4252 static std::unique_ptr<CrxDownloader> Create(
4253 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:124254 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianua8926bf2018-03-09 21:02:534255 return std::make_unique<MockCrxDownloader>();
Sorin Jianu4ab7c292017-06-15 18:40:214256 }
4257
Sorin Jianua8926bf2018-03-09 21:02:534258 MockCrxDownloader() : CrxDownloader(nullptr) {}
Sorin Jianu4ab7c292017-06-15 18:40:214259
4260 private:
4261 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
4262 };
4263
Sorin Jianua8926bf2018-03-09 21:02:534264 class MockPingManager : public MockPingManagerImpl {
Sorin Jianu4ab7c292017-06-15 18:40:214265 public:
Sorin Jianua8926bf2018-03-09 21:02:534266 explicit MockPingManager(scoped_refptr<Configurator> config)
4267 : MockPingManagerImpl(config) {}
Sorin Jianu560d5022018-02-12 23:11:544268
4269 protected:
Sorin Jianua8926bf2018-03-09 21:02:534270 ~MockPingManager() override {
Sorin Jianu039032b2018-10-12 21:48:134271 EXPECT_EQ(1u, events().size());
4272
4273 // "<event eventtype="42" eventresult="1" errorcode="1877345072"/>"
4274 const auto& event = events()[0];
4275 EXPECT_EQ(42, event.FindKey("eventtype")->GetInt());
4276 EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
4277 EXPECT_EQ(1877345072, event.FindKey("errorcode")->GetInt());
Sorin Jianu4ab7c292017-06-15 18:40:214278 }
4279 };
4280
Sorin Jianu2fe49a02019-11-25 19:15:564281 // Unpack the CRX to mock an existing install to be updated. The action to
4282 // run is going to be resolved relative to this directory.
Sorin Jianu4ab7c292017-06-15 18:40:214283 base::FilePath unpack_path;
4284 {
4285 base::RunLoop runloop;
Sorin Jianua8ef73d2017-11-02 16:55:174286 base::OnceClosure quit_closure = runloop.QuitClosure();
Sorin Jianu4ab7c292017-06-15 18:40:214287
Joshua Pawlicki6d764422018-02-21 15:23:104288 auto config = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu7c22795b2018-04-26 22:16:524289 auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
Sorin Jianue5bfb5b2017-06-20 21:30:564290 std::vector<uint8_t>(std::begin(gjpm_hash), std::end(gjpm_hash)),
Joshua Pawlicki6d764422018-02-21 15:23:104291 TestFilePath("runaction_test_win.crx3"), nullptr,
Joshua Pawlickid5409e12019-04-06 00:23:114292 config->GetUnzipperFactory()->Create(),
Joshua Pawlickiafaa2922019-09-03 18:50:234293 config->GetPatcherFactory()->Create(), crx_file::VerifierFormat::CRX3);
Sorin Jianu4ab7c292017-06-15 18:40:214294
Sorin Jianua8ef73d2017-11-02 16:55:174295 component_unpacker->Unpack(base::BindOnce(
4296 [](base::FilePath* unpack_path, base::OnceClosure quit_closure,
Sorin Jianu4ab7c292017-06-15 18:40:214297 const ComponentUnpacker::Result& result) {
4298 EXPECT_EQ(UnpackerError::kNone, result.error);
4299 EXPECT_EQ(0, result.extended_error);
4300 *unpack_path = result.unpack_path;
Sorin Jianua8ef73d2017-11-02 16:55:174301 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:214302 },
4303 &unpack_path, runloop.QuitClosure()));
4304
4305 runloop.Run();
4306 }
4307
4308 EXPECT_FALSE(unpack_path.empty());
4309 EXPECT_TRUE(base::DirectoryExists(unpack_path));
4310 int64_t file_size = 0;
Sorin Jianue5bfb5b2017-06-20 21:30:564311 EXPECT_TRUE(base::GetFileSize(unpack_path.AppendASCII("ChromeRecovery.crx3"),
4312 &file_size));
4313 EXPECT_EQ(44582, file_size);
Sorin Jianu4ab7c292017-06-15 18:40:214314
4315 base::ScopedTempDir unpack_path_owner;
4316 EXPECT_TRUE(unpack_path_owner.Set(unpack_path));
4317
4318 scoped_refptr<UpdateClient> update_client =
4319 base::MakeRefCounted<UpdateClientImpl>(
Sorin Jianua8926bf2018-03-09 21:02:534320 config(), base::MakeRefCounted<MockPingManager>(config()),
4321 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
Sorin Jianu4ab7c292017-06-15 18:40:214322
Sorin Jianue5bfb5b2017-06-20 21:30:564323 const std::vector<std::string> ids = {"gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
Sorin Jianu4ab7c292017-06-15 18:40:214324 update_client->Update(
4325 ids,
Sorin Jianua8ef73d2017-11-02 16:55:174326 base::BindOnce(
Sorin Jianu4ab7c292017-06-15 18:40:214327 [](const base::FilePath& unpack_path,
Sorin Jianu7c22795b2018-04-26 22:16:524328 const std::vector<std::string>& ids) {
Sorin Jianu2fe49a02019-11-25 19:15:564329 auto action_handler = base::MakeRefCounted<MockActionHandler>();
4330 EXPECT_CALL(*action_handler, Handle(_, _, _))
4331 .WillOnce([](const base::FilePath& action,
4332 const std::string& session_id,
4333 ActionHandler::Callback callback) {
4334 EXPECT_EQ("ChromeRecovery.crx3",
4335 action.BaseName().MaybeAsASCII());
4336 EXPECT_TRUE(!session_id.empty());
4337 std::move(callback).Run(true, 1877345072, 0);
4338 });
4339
Sorin Jianu73900242018-08-17 01:11:534340 CrxComponent crx;
4341 crx.name = "test_niea";
4342 crx.pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
4343 crx.version = base::Version("1.0");
4344 crx.installer =
Sorin Jianu4ab7c292017-06-15 18:40:214345 base::MakeRefCounted<ReadOnlyTestInstaller>(unpack_path);
Sorin Jianu2fe49a02019-11-25 19:15:564346 crx.action_handler = action_handler;
Joshua Pawlickiafaa2922019-09-03 18:50:234347 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
Sorin Jianu73900242018-08-17 01:11:534348 return std::vector<base::Optional<CrxComponent>>{crx};
Sorin Jianu4ab7c292017-06-15 18:40:214349 },
4350 unpack_path),
Sorin Jianudfb12a42020-03-10 04:12:034351 {}, false,
Sorin Jianua8ef73d2017-11-02 16:55:174352 base::BindOnce(
4353 [](base::OnceClosure quit_closure, Error error) {
Sorin Jianu4ab7c292017-06-15 18:40:214354 EXPECT_EQ(Error::NONE, error);
Sorin Jianua8ef73d2017-11-02 16:55:174355 std::move(quit_closure).Run();
Sorin Jianu4ab7c292017-06-15 18:40:214356 },
4357 quit_closure()));
4358
4359 RunThreads();
4360}
4361
Joshua Pawlickica4f8fa12020-02-25 23:46:064362// Tests that custom response attributes are visible to observers.
4363TEST_F(UpdateClientTest, CustomAttributeNoUpdate) {
4364 class DataCallbackMock {
4365 public:
4366 static std::vector<base::Optional<CrxComponent>> Callback(
4367 const std::vector<std::string>& ids) {
4368 CrxComponent crx;
4369 crx.name = "test_jebg";
4370 crx.pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
4371 crx.version = base::Version("0.9");
4372 crx.installer = base::MakeRefCounted<TestInstaller>();
4373 crx.crx_format_requirement = crx_file::VerifierFormat::CRX3;
4374 std::vector<base::Optional<CrxComponent>> component = {crx};
4375 return component;
4376 }
4377 };
4378
4379 class CompletionCallbackMock {
4380 public:
4381 static void Callback(base::OnceClosure quit_closure, Error error) {
4382 EXPECT_EQ(Error::NONE, error);
4383 std::move(quit_closure).Run();
4384 }
4385 };
4386
4387 class MockUpdateChecker : public UpdateChecker {
4388 public:
4389 static std::unique_ptr<UpdateChecker> Create(
4390 scoped_refptr<Configurator> config,
4391 PersistedData* metadata) {
4392 return std::make_unique<MockUpdateChecker>();
4393 }
4394
4395 void CheckForUpdates(
4396 const std::string& session_id,
4397 const std::vector<std::string>& ids_to_check,
4398 const IdToComponentPtrMap& components,
4399 const base::flat_map<std::string, std::string>& additional_attributes,
4400 bool enabled_component_updates,
4401 UpdateCheckCallback update_check_callback) override {
4402 EXPECT_FALSE(session_id.empty());
4403 EXPECT_TRUE(enabled_component_updates);
4404 EXPECT_EQ(1u, ids_to_check.size());
4405 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
4406 EXPECT_EQ(id, ids_to_check.front());
4407 EXPECT_EQ(1u, components.count(id));
4408
4409 auto& component = components.at(id);
4410
4411 EXPECT_TRUE(component->is_foreground());
4412
4413 ProtocolParser::Result result;
4414 result.extension_id = id;
4415 result.status = "noupdate";
4416 result.custom_attributes["_example"] = "example_value";
4417
4418 ProtocolParser::Results results;
4419 results.list.push_back(result);
4420
4421 base::ThreadTaskRunnerHandle::Get()->PostTask(
4422 FROM_HERE, base::BindOnce(std::move(update_check_callback), results,
4423 ErrorCategory::kNone, 0, 0));
4424 }
4425 };
4426
4427 class MockCrxDownloader : public CrxDownloader {
4428 public:
4429 static std::unique_ptr<CrxDownloader> Create(
4430 bool is_background_download,
4431 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
4432 return std::make_unique<MockCrxDownloader>();
4433 }
4434
4435 MockCrxDownloader() : CrxDownloader(nullptr) {}
4436
4437 private:
4438 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
4439 };
4440
4441 class MockPingManager : public MockPingManagerImpl {
4442 public:
4443 explicit MockPingManager(scoped_refptr<Configurator> config)
4444 : MockPingManagerImpl(config) {}
4445
4446 protected:
4447 ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
4448 };
4449
4450 scoped_refptr<UpdateClient> update_client =
4451 base::MakeRefCounted<UpdateClientImpl>(
4452 config(), base::MakeRefCounted<MockPingManager>(config()),
4453 &MockUpdateChecker::Create, &MockCrxDownloader::Create);
4454
4455 class Observer : public UpdateClient::Observer {
4456 public:
4457 explicit Observer(scoped_refptr<UpdateClient> update_client)
4458 : update_client_(update_client) {}
4459
4460 void OnEvent(Events event, const std::string& id) override {
4461 if (event != Events::COMPONENT_NOT_UPDATED)
4462 return;
4463 ++calls;
4464 CrxUpdateItem item;
4465 EXPECT_TRUE(update_client_->GetCrxUpdateState(
4466 "jebgalgnebhfojomionfpkfelancnnkf", &item));
4467 EXPECT_EQ("example_value", item.custom_updatecheck_data["_example"]);
4468 }
4469
4470 int calls = 0;
4471
4472 private:
4473 scoped_refptr<UpdateClient> update_client_;
4474 };
4475
4476 Observer observer(update_client);
4477 update_client->AddObserver(&observer);
4478
4479 const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"};
4480 update_client->Update(
Sorin Jianudfb12a42020-03-10 04:12:034481 ids, base::BindOnce(&DataCallbackMock::Callback), {}, true,
Joshua Pawlickica4f8fa12020-02-25 23:46:064482 base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
4483
4484 RunThreads();
4485
4486 update_client->RemoveObserver(&observer);
4487
4488 EXPECT_EQ(1, observer.calls);
4489}
sorin9797aba2015-04-17 17:15:034490} // namespace update_client