blob: c2f46d10432b4f382b772d1612d11a3fe2995f47 [file] [log] [blame]
sorin7c717622015-05-26 19:59:091// 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
dchenga0ee5fb82016-04-26 02:46:555#include "components/component_updater/component_updater_service.h"
6
sorin7c717622015-05-26 19:59:097#include <limits>
Sorin Jianu990ee142017-06-02 22:34:088#include <memory>
sorin7c717622015-05-26 19:59:099#include <string>
Sorin Jianua8ef73d2017-11-02 16:55:1710#include <utility>
sorin7c717622015-05-26 19:59:0911#include <vector>
12
13#include "base/bind.h"
14#include "base/bind_helpers.h"
15#include "base/files/file_path.h"
16#include "base/files/file_util.h"
17#include "base/macros.h"
18#include "base/memory/ref_counted.h"
sorin7c717622015-05-26 19:59:0919#include "base/run_loop.h"
fdoraydc4d9942017-05-12 20:13:5020#include "base/task_scheduler/post_task.h"
sorin85953dc2016-03-10 00:32:4821#include "base/test/histogram_tester.h"
fdoraydc4d9942017-05-12 20:13:5022#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0123#include "base/threading/thread_task_runner_handle.h"
sorin7c717622015-05-26 19:59:0924#include "base/values.h"
sorin7c717622015-05-26 19:59:0925#include "components/component_updater/component_updater_service_internal.h"
26#include "components/update_client/test_configurator.h"
27#include "components/update_client/test_installer.h"
28#include "components/update_client/update_client.h"
sorin7b8650522016-11-02 18:23:4129#include "components/update_client/update_client_errors.h"
sorin7c717622015-05-26 19:59:0930#include "testing/gmock/include/gmock/gmock.h"
31#include "testing/gtest/include/gtest/gtest.h"
32
33using Configurator = update_client::Configurator;
sorin2892f7212016-11-07 18:59:4334using Result = update_client::CrxInstaller::Result;
sorin7c717622015-05-26 19:59:0935using TestConfigurator = update_client::TestConfigurator;
36using UpdateClient = update_client::UpdateClient;
37
38using ::testing::_;
39using ::testing::AnyNumber;
40using ::testing::Invoke;
41using ::testing::Mock;
42using ::testing::Return;
Sorin Jianua8ef73d2017-11-02 16:55:1743using ::testing::Unused;
sorin7c717622015-05-26 19:59:0944
45namespace component_updater {
46
47class MockInstaller : public CrxInstaller {
48 public:
49 MockInstaller();
50
Sorin Jianua8ef73d2017-11-02 16:55:1751 // gMock does not support mocking functions with parameters which have
52 // move semantics. This function is a shim to work around it.
53 void Install(const base::FilePath& unpack_path,
54 const std::string& public_key,
55 update_client::CrxInstaller::Callback callback) {
56 DoInstall(unpack_path, callback);
57 }
58
sorin7c717622015-05-26 19:59:0959 MOCK_METHOD1(OnUpdateError, void(int error));
Sorin Jianua8ef73d2017-11-02 16:55:1760 MOCK_METHOD2(DoInstall,
Sorin Jianu7aa6d1f2017-10-13 20:29:2961 void(const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:4162 const update_client::CrxInstaller::Callback& callback));
sorin7c717622015-05-26 19:59:0963 MOCK_METHOD2(GetInstalledFile,
64 bool(const std::string& file, base::FilePath* installed_file));
65 MOCK_METHOD0(Uninstall, bool());
66
67 private:
68 ~MockInstaller() override;
69};
70
71class MockUpdateClient : public UpdateClient {
72 public:
73 MockUpdateClient();
Vladislav Kuzkokov12eca792017-10-20 12:45:3874
Sorin Jianua8ef73d2017-11-02 16:55:1775 // gMock does not support mocking functions with parameters which have
76 // move semantics. This function is a shim to work around it.
Vladislav Kuzkokov12eca792017-10-20 12:45:3877 void Install(const std::string& id,
Sorin Jianua8ef73d2017-11-02 16:55:1778 CrxDataCallback crx_data_callback,
Vladislav Kuzkokov12eca792017-10-20 12:45:3879 Callback callback) override {
Sorin Jianua8ef73d2017-11-02 16:55:1780 DoInstall(id, std::move(crx_data_callback));
Vladislav Kuzkokov12eca792017-10-20 12:45:3881 std::move(callback).Run(update_client::Error::NONE);
82 }
83
84 void Update(const std::vector<std::string>& ids,
Sorin Jianua8ef73d2017-11-02 16:55:1785 CrxDataCallback crx_data_callback,
Sorin Jianub41a592a2018-03-02 16:30:2786 bool is_foreground,
Vladislav Kuzkokov12eca792017-10-20 12:45:3887 Callback callback) override {
Sorin Jianub41a592a2018-03-02 16:30:2788 // All update calls initiated by the component update service are
89 // automatically triggered as background updates without user intervention.
90 EXPECT_FALSE(is_foreground);
Sorin Jianua8ef73d2017-11-02 16:55:1791 DoUpdate(ids, std::move(crx_data_callback));
Vladislav Kuzkokov12eca792017-10-20 12:45:3892 std::move(callback).Run(update_client::Error::NONE);
93 }
94
95 void SendUninstallPing(const std::string& id,
96 const base::Version& version,
97 int reason,
98 Callback callback) {
99 DoSendUninstallPing(id, version, reason);
100 std::move(callback).Run(update_client::Error::NONE);
101 }
102
sorin7c717622015-05-26 19:59:09103 MOCK_METHOD1(AddObserver, void(Observer* observer));
104 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
Vladislav Kuzkokov12eca792017-10-20 12:45:38105 MOCK_METHOD2(DoInstall,
sorin7c717622015-05-26 19:59:09106 void(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:38107 const CrxDataCallback& crx_data_callback));
108 MOCK_METHOD2(DoUpdate,
sorin7c717622015-05-26 19:59:09109 void(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38110 const CrxDataCallback& crx_data_callback));
sorin7c717622015-05-26 19:59:09111 MOCK_CONST_METHOD2(GetCrxUpdateState,
112 bool(const std::string& id, CrxUpdateItem* update_item));
113 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
sorinecaad3e2015-11-13 19:15:52114 MOCK_METHOD0(Stop, void());
Vladislav Kuzkokov12eca792017-10-20 12:45:38115 MOCK_METHOD3(DoSendUninstallPing,
sorin8037ac8c2017-04-19 16:28:00116 void(const std::string& id,
117 const base::Version& version,
Vladislav Kuzkokov12eca792017-10-20 12:45:38118 int reason));
sorin7c717622015-05-26 19:59:09119
120 private:
121 ~MockUpdateClient() override;
122};
123
124class MockServiceObserver : public ServiceObserver {
125 public:
126 MockServiceObserver();
127 ~MockServiceObserver() override;
128
129 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
130};
131
132class ComponentUpdaterTest : public testing::Test {
133 public:
134 ComponentUpdaterTest();
135 ~ComponentUpdaterTest() override;
136
137 void SetUp() override;
138
139 void TearDown() override;
140
141 // Makes the full path to a component updater test file.
142 const base::FilePath test_file(const char* file);
143
144 MockUpdateClient& update_client() { return *update_client_; }
145 ComponentUpdateService& component_updater() { return *component_updater_; }
146 scoped_refptr<TestConfigurator> configurator() const { return config_; }
Sorin Jianua8ef73d2017-11-02 16:55:17147 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
sorin7c717622015-05-26 19:59:09148 static void ReadyCallback() {}
149
150 protected:
151 void RunThreads();
152
153 private:
fdoraydc4d9942017-05-12 20:13:50154 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin7c717622015-05-26 19:59:09155 base::RunLoop runloop_;
sorin7c717622015-05-26 19:59:09156
Sorin Jianucc048f892017-07-26 02:05:54157 scoped_refptr<TestConfigurator> config_ =
158 base::MakeRefCounted<TestConfigurator>();
159 scoped_refptr<MockUpdateClient> update_client_ =
160 base::MakeRefCounted<MockUpdateClient>();
dchenga0ee5fb82016-04-26 02:46:55161 std::unique_ptr<ComponentUpdateService> component_updater_;
sorin7c717622015-05-26 19:59:09162
163 DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterTest);
164};
165
166class OnDemandTester {
167 public:
sorin4c520182016-08-19 17:27:44168 void OnDemand(ComponentUpdateService* cus, const std::string& id);
sorin7b8650522016-11-02 18:23:41169 update_client::Error error() const { return error_; }
sorin4c520182016-08-19 17:27:44170
171 private:
sorin7b8650522016-11-02 18:23:41172 void OnDemandComplete(update_client::Error error);
sorin4c520182016-08-19 17:27:44173
sorin7b8650522016-11-02 18:23:41174 update_client::Error error_ = update_client::Error::NONE;
sorin7c717622015-05-26 19:59:09175};
176
177MockInstaller::MockInstaller() {
178}
179
180MockInstaller::~MockInstaller() {
181}
182
183MockUpdateClient::MockUpdateClient() {
184}
185
186MockUpdateClient::~MockUpdateClient() {
187}
188
189MockServiceObserver::MockServiceObserver() {
190}
191
192MockServiceObserver::~MockServiceObserver() {
193}
194
sorin4c520182016-08-19 17:27:44195void OnDemandTester::OnDemand(ComponentUpdateService* cus,
sorin7c717622015-05-26 19:59:09196 const std::string& id) {
sorin4c520182016-08-19 17:27:44197 cus->GetOnDemandUpdater().OnDemandUpdate(
Sorin Jianua8ef73d2017-11-02 16:55:17198 id, base::BindOnce(&OnDemandTester::OnDemandComplete,
199 base::Unretained(this)));
sorin4c520182016-08-19 17:27:44200}
201
sorin7b8650522016-11-02 18:23:41202void OnDemandTester::OnDemandComplete(update_client::Error error) {
sorin4c520182016-08-19 17:27:44203 error_ = error;
sorin7c717622015-05-26 19:59:09204}
205
dchenga0ee5fb82016-04-26 02:46:55206std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
Sorin Jianu49126332018-02-13 17:07:42207 scoped_refptr<Configurator> config) {
sorin7c717622015-05-26 19:59:09208 DCHECK(config);
Gyuyoung Kim6afb5082018-01-19 13:35:57209 return std::make_unique<CrxUpdateService>(
Sorin Jianua8ef73d2017-11-02 16:55:17210 config, base::MakeRefCounted<MockUpdateClient>());
sorin7c717622015-05-26 19:59:09211}
212
Sorin Jianucc048f892017-07-26 02:05:54213ComponentUpdaterTest::ComponentUpdaterTest() {
sorin7c717622015-05-26 19:59:09214 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
Sorin Jianuebd652462017-07-23 02:00:58215 component_updater_ =
Gyuyoung Kim6afb5082018-01-19 13:35:57216 std::make_unique<CrxUpdateService>(config_, update_client_);
sorin7c717622015-05-26 19:59:09217}
218
219ComponentUpdaterTest::~ComponentUpdaterTest() {
220 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
sorin7c717622015-05-26 19:59:09221 component_updater_.reset();
222}
223
224void ComponentUpdaterTest::SetUp() {
225}
226
227void ComponentUpdaterTest::TearDown() {
228}
229
230void ComponentUpdaterTest::RunThreads() {
231 runloop_.Run();
232}
233
234TEST_F(ComponentUpdaterTest, AddObserver) {
235 MockServiceObserver observer;
236 EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52237 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09238 component_updater().AddObserver(&observer);
239}
240
241TEST_F(ComponentUpdaterTest, RemoveObserver) {
242 MockServiceObserver observer;
243 EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52244 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09245 component_updater().RemoveObserver(&observer);
246}
247
248// Tests that UpdateClient::Update is called by the timer loop when
249// components are registered, and the component update starts.
250// Also tests that Uninstall is called when a component is unregistered.
251TEST_F(ComponentUpdaterTest, RegisterComponent) {
252 class LoopHandler {
253 public:
Sorin Jianua8ef73d2017-11-02 16:55:17254 LoopHandler(int max_cnt, base::OnceClosure quit_closure)
255 : max_cnt_(max_cnt), quit_closure_(std::move(quit_closure)) {}
sorin7c717622015-05-26 19:59:09256
Sorin Jianua8ef73d2017-11-02 16:55:17257 void OnUpdate(const std::vector<std::string>& ids, Unused) {
sorin7c717622015-05-26 19:59:09258 static int cnt = 0;
259 ++cnt;
260 if (cnt >= max_cnt_)
Sorin Jianua8ef73d2017-11-02 16:55:17261 std::move(quit_closure_).Run();
sorin7c717622015-05-26 19:59:09262 }
263
264 private:
265 const int max_cnt_;
Sorin Jianua8ef73d2017-11-02 16:55:17266 base::OnceClosure quit_closure_;
sorin7c717622015-05-26 19:59:09267 };
268
sorin85953dc2016-03-10 00:32:48269 base::HistogramTester ht;
270
Sorin Jianua8ef73d2017-11-02 16:55:17271 scoped_refptr<MockInstaller> installer =
272 base::MakeRefCounted<MockInstaller>();
sorin7c717622015-05-26 19:59:09273 EXPECT_CALL(*installer, Uninstall()).WillOnce(Return(true));
274
275 using update_client::jebg_hash;
276 using update_client::abag_hash;
277
278 const std::string id1 = "abagagagagagagagagagagagagagagag";
279 const std::string id2 = "jebgalgnebhfojomionfpkfelancnnkf";
280 std::vector<std::string> ids;
281 ids.push_back(id1);
282 ids.push_back(id2);
283
284 CrxComponent crx_component1;
285 crx_component1.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
pwnall15745b312016-08-19 21:45:29286 crx_component1.version = base::Version("1.0");
sorin7c717622015-05-26 19:59:09287 crx_component1.installer = installer;
288
289 CrxComponent crx_component2;
290 crx_component2.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29291 crx_component2.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09292 crx_component2.installer = installer;
293
294 // Quit after two update checks have fired.
295 LoopHandler loop_handler(2, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38296 EXPECT_CALL(update_client(), DoUpdate(ids, _))
sorin7c717622015-05-26 19:59:09297 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
298
299 EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
sorinecaad3e2015-11-13 19:15:52300 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09301
302 EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
303 EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
304
305 RunThreads();
sorin7c717622015-05-26 19:59:09306 EXPECT_TRUE(component_updater().UnregisterComponent(id1));
sorin85953dc2016-03-10 00:32:48307
308 ht.ExpectUniqueSample("ComponentUpdater.Calls", 1, 2);
309 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 2);
310 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 2);
sorin7c717622015-05-26 19:59:09311}
312
313// Tests that on-demand updates invoke UpdateClient::Install.
314TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
315 class LoopHandler {
316 public:
sorin7b8650522016-11-02 18:23:41317 explicit LoopHandler(int max_cnt) : max_cnt_(max_cnt) {}
sorin7c717622015-05-26 19:59:09318
Sorin Jianua8ef73d2017-11-02 16:55:17319 void OnInstall(const std::string& ids, Unused) {
sorin7c717622015-05-26 19:59:09320 static int cnt = 0;
321 ++cnt;
sorin4c520182016-08-19 17:27:44322 if (cnt >= max_cnt_) {
323 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58324 FROM_HERE,
325 base::BindOnce(&LoopHandler::Quit, base::Unretained(this)));
sorin4c520182016-08-19 17:27:44326 }
sorin7c717622015-05-26 19:59:09327 }
328
329 private:
Gabriel Charette53a9ef812017-07-26 12:36:23330 void Quit() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
sorin4c520182016-08-19 17:27:44331
sorin7c717622015-05-26 19:59:09332 const int max_cnt_;
sorin7c717622015-05-26 19:59:09333 };
334
sorin85953dc2016-03-10 00:32:48335 base::HistogramTester ht;
336
sorin7c717622015-05-26 19:59:09337 auto config = configurator();
338 config->SetInitialDelay(3600);
339
340 auto& cus = component_updater();
341
sorin4c520182016-08-19 17:27:44342 // Tests calling OnDemand for an unregistered component. This call results in
343 // an error, which is recorded by the OnDemandTester instance. Since the
344 // component was not registered, the call is ignored for UMA metrics.
345 OnDemandTester ondemand_tester_component_not_registered;
346 ondemand_tester_component_not_registered.OnDemand(
347 &cus, "ihfokbkgjpifnbbojhneepfflplebdkc");
sorin7c717622015-05-26 19:59:09348
sorin4c520182016-08-19 17:27:44349 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
sorin7c717622015-05-26 19:59:09350
351 using update_client::jebg_hash;
352 CrxComponent crx_component;
353 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29354 crx_component.version = base::Version("0.9");
Sorin Jianua8ef73d2017-11-02 16:55:17355 crx_component.installer = base::MakeRefCounted<MockInstaller>();
sorin7c717622015-05-26 19:59:09356
sorin4c520182016-08-19 17:27:44357 LoopHandler loop_handler(1);
Vladislav Kuzkokov12eca792017-10-20 12:45:38358 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09359 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52360 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09361
362 EXPECT_TRUE(cus.RegisterComponent(crx_component));
sorin4c520182016-08-19 17:27:44363 OnDemandTester ondemand_tester;
364 ondemand_tester.OnDemand(&cus, id);
sorin7c717622015-05-26 19:59:09365
sorin4c520182016-08-19 17:27:44366 base::RunLoop().Run();
367
sorin7b8650522016-11-02 18:23:41368 EXPECT_EQ(update_client::Error::INVALID_ARGUMENT,
369 ondemand_tester_component_not_registered.error());
370 EXPECT_EQ(update_client::Error::NONE, ondemand_tester.error());
sorin85953dc2016-03-10 00:32:48371
372 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
373 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
374 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09375}
376
377// Tests that throttling an update invokes UpdateClient::Install.
378TEST_F(ComponentUpdaterTest, MaybeThrottle) {
379 class LoopHandler {
380 public:
Sorin Jianua8ef73d2017-11-02 16:55:17381 LoopHandler(int max_cnt, base::OnceClosure quit_closure)
382 : max_cnt_(max_cnt), quit_closure_(std::move(quit_closure)) {}
sorin7c717622015-05-26 19:59:09383
Sorin Jianua8ef73d2017-11-02 16:55:17384 void OnInstall(const std::string& ids, Unused) {
sorin7c717622015-05-26 19:59:09385 static int cnt = 0;
386 ++cnt;
387 if (cnt >= max_cnt_)
Sorin Jianua8ef73d2017-11-02 16:55:17388 std::move(quit_closure_).Run();
sorin7c717622015-05-26 19:59:09389 }
390
391 private:
392 const int max_cnt_;
Sorin Jianua8ef73d2017-11-02 16:55:17393 base::OnceClosure quit_closure_;
sorin7c717622015-05-26 19:59:09394 };
395
sorin85953dc2016-03-10 00:32:48396 base::HistogramTester ht;
397
sorin7c717622015-05-26 19:59:09398 auto config = configurator();
399 config->SetInitialDelay(3600);
400
Sorin Jianua8ef73d2017-11-02 16:55:17401 scoped_refptr<MockInstaller> installer =
402 base::MakeRefCounted<MockInstaller>();
sorin7c717622015-05-26 19:59:09403
404 using update_client::jebg_hash;
405 CrxComponent crx_component;
406 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29407 crx_component.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09408 crx_component.installer = installer;
409
410 LoopHandler loop_handler(1, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38411 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09412 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52413 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09414
415 EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
416 component_updater().MaybeThrottle(
417 "jebgalgnebhfojomionfpkfelancnnkf",
Sorin Jianua8ef73d2017-11-02 16:55:17418 base::BindOnce(&ComponentUpdaterTest::ReadyCallback));
sorin7c717622015-05-26 19:59:09419
420 RunThreads();
sorin85953dc2016-03-10 00:32:48421
422 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
423 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
424 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09425}
426
427} // namespace component_updater