blob: fafb1bb499f1b70b95e75bf2ba070555404596ba [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>
10#include <vector>
11
12#include "base/bind.h"
13#include "base/bind_helpers.h"
14#include "base/files/file_path.h"
15#include "base/files/file_util.h"
16#include "base/macros.h"
dchenga0ee5fb82016-04-26 02:46:5517#include "base/memory/ptr_util.h"
sorin7c717622015-05-26 19:59:0918#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;
43
44namespace component_updater {
45
46class MockInstaller : public CrxInstaller {
47 public:
48 MockInstaller();
49
sorin7c717622015-05-26 19:59:0950 MOCK_METHOD1(OnUpdateError, void(int error));
Sorin Jianuea5534e92017-10-27 01:40:2851 MOCK_METHOD3(Install,
Sorin Jianu7aa6d1f2017-10-13 20:29:2952 void(const base::FilePath& unpack_path,
Sorin Jianuea5534e92017-10-27 01:40:2853 const std::string& public_key,
Sorin Jianuf40ab4b32017-10-06 22:53:4154 const update_client::CrxInstaller::Callback& callback));
sorin7c717622015-05-26 19:59:0955 MOCK_METHOD2(GetInstalledFile,
56 bool(const std::string& file, base::FilePath* installed_file));
57 MOCK_METHOD0(Uninstall, bool());
58
59 private:
60 ~MockInstaller() override;
61};
62
63class MockUpdateClient : public UpdateClient {
64 public:
65 MockUpdateClient();
Vladislav Kuzkokov12eca792017-10-20 12:45:3866
67 void Install(const std::string& id,
68 const CrxDataCallback& crx_data_callback,
69 Callback callback) override {
70 DoInstall(id, crx_data_callback);
71 std::move(callback).Run(update_client::Error::NONE);
72 }
73
74 void Update(const std::vector<std::string>& ids,
75 const CrxDataCallback& crx_data_callback,
76 Callback callback) override {
77 DoUpdate(ids, crx_data_callback);
78 std::move(callback).Run(update_client::Error::NONE);
79 }
80
81 void SendUninstallPing(const std::string& id,
82 const base::Version& version,
83 int reason,
84 Callback callback) {
85 DoSendUninstallPing(id, version, reason);
86 std::move(callback).Run(update_client::Error::NONE);
87 }
88
sorin7c717622015-05-26 19:59:0989 MOCK_METHOD1(AddObserver, void(Observer* observer));
90 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
Vladislav Kuzkokov12eca792017-10-20 12:45:3891 MOCK_METHOD2(DoInstall,
sorin7c717622015-05-26 19:59:0992 void(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:3893 const CrxDataCallback& crx_data_callback));
94 MOCK_METHOD2(DoUpdate,
sorin7c717622015-05-26 19:59:0995 void(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:3896 const CrxDataCallback& crx_data_callback));
sorin7c717622015-05-26 19:59:0997 MOCK_CONST_METHOD2(GetCrxUpdateState,
98 bool(const std::string& id, CrxUpdateItem* update_item));
99 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
sorinecaad3e2015-11-13 19:15:52100 MOCK_METHOD0(Stop, void());
Vladislav Kuzkokov12eca792017-10-20 12:45:38101 MOCK_METHOD3(DoSendUninstallPing,
sorin8037ac8c2017-04-19 16:28:00102 void(const std::string& id,
103 const base::Version& version,
Vladislav Kuzkokov12eca792017-10-20 12:45:38104 int reason));
sorin7c717622015-05-26 19:59:09105
106 private:
107 ~MockUpdateClient() override;
108};
109
110class MockServiceObserver : public ServiceObserver {
111 public:
112 MockServiceObserver();
113 ~MockServiceObserver() override;
114
115 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
116};
117
118class ComponentUpdaterTest : public testing::Test {
119 public:
120 ComponentUpdaterTest();
121 ~ComponentUpdaterTest() override;
122
123 void SetUp() override;
124
125 void TearDown() override;
126
127 // Makes the full path to a component updater test file.
128 const base::FilePath test_file(const char* file);
129
130 MockUpdateClient& update_client() { return *update_client_; }
131 ComponentUpdateService& component_updater() { return *component_updater_; }
132 scoped_refptr<TestConfigurator> configurator() const { return config_; }
133 base::Closure quit_closure() const { return quit_closure_; }
134 static void ReadyCallback() {}
135
136 protected:
137 void RunThreads();
138
139 private:
fdoraydc4d9942017-05-12 20:13:50140 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin7c717622015-05-26 19:59:09141 base::RunLoop runloop_;
Sorin Jianucc048f892017-07-26 02:05:54142 const base::Closure quit_closure_ = runloop_.QuitClosure();
sorin7c717622015-05-26 19:59:09143
Sorin Jianucc048f892017-07-26 02:05:54144 scoped_refptr<TestConfigurator> config_ =
145 base::MakeRefCounted<TestConfigurator>();
146 scoped_refptr<MockUpdateClient> update_client_ =
147 base::MakeRefCounted<MockUpdateClient>();
dchenga0ee5fb82016-04-26 02:46:55148 std::unique_ptr<ComponentUpdateService> component_updater_;
sorin7c717622015-05-26 19:59:09149
150 DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterTest);
151};
152
153class OnDemandTester {
154 public:
sorin4c520182016-08-19 17:27:44155 void OnDemand(ComponentUpdateService* cus, const std::string& id);
sorin7b8650522016-11-02 18:23:41156 update_client::Error error() const { return error_; }
sorin4c520182016-08-19 17:27:44157
158 private:
sorin7b8650522016-11-02 18:23:41159 void OnDemandComplete(update_client::Error error);
sorin4c520182016-08-19 17:27:44160
sorin7b8650522016-11-02 18:23:41161 update_client::Error error_ = update_client::Error::NONE;
sorin7c717622015-05-26 19:59:09162};
163
164MockInstaller::MockInstaller() {
165}
166
167MockInstaller::~MockInstaller() {
168}
169
170MockUpdateClient::MockUpdateClient() {
171}
172
173MockUpdateClient::~MockUpdateClient() {
174}
175
176MockServiceObserver::MockServiceObserver() {
177}
178
179MockServiceObserver::~MockServiceObserver() {
180}
181
sorin4c520182016-08-19 17:27:44182void OnDemandTester::OnDemand(ComponentUpdateService* cus,
sorin7c717622015-05-26 19:59:09183 const std::string& id) {
sorin4c520182016-08-19 17:27:44184 cus->GetOnDemandUpdater().OnDemandUpdate(
185 id,
186 base::Bind(&OnDemandTester::OnDemandComplete, base::Unretained(this)));
187}
188
sorin7b8650522016-11-02 18:23:41189void OnDemandTester::OnDemandComplete(update_client::Error error) {
sorin4c520182016-08-19 17:27:44190 error_ = error;
sorin7c717622015-05-26 19:59:09191}
192
dchenga0ee5fb82016-04-26 02:46:55193std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
sorin7c717622015-05-26 19:59:09194 const scoped_refptr<Configurator>& config) {
195 DCHECK(config);
ricea85ec57952016-08-31 09:34:10196 return base::MakeUnique<CrxUpdateService>(config, new MockUpdateClient());
sorin7c717622015-05-26 19:59:09197}
198
Sorin Jianucc048f892017-07-26 02:05:54199ComponentUpdaterTest::ComponentUpdaterTest() {
sorin7c717622015-05-26 19:59:09200 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
Sorin Jianuebd652462017-07-23 02:00:58201 component_updater_ =
202 base::MakeUnique<CrxUpdateService>(config_, update_client_);
sorin7c717622015-05-26 19:59:09203}
204
205ComponentUpdaterTest::~ComponentUpdaterTest() {
206 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
sorin7c717622015-05-26 19:59:09207 component_updater_.reset();
208}
209
210void ComponentUpdaterTest::SetUp() {
211}
212
213void ComponentUpdaterTest::TearDown() {
214}
215
216void ComponentUpdaterTest::RunThreads() {
217 runloop_.Run();
218}
219
220TEST_F(ComponentUpdaterTest, AddObserver) {
221 MockServiceObserver observer;
222 EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52223 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09224 component_updater().AddObserver(&observer);
225}
226
227TEST_F(ComponentUpdaterTest, RemoveObserver) {
228 MockServiceObserver observer;
229 EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52230 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09231 component_updater().RemoveObserver(&observer);
232}
233
234// Tests that UpdateClient::Update is called by the timer loop when
235// components are registered, and the component update starts.
236// Also tests that Uninstall is called when a component is unregistered.
237TEST_F(ComponentUpdaterTest, RegisterComponent) {
238 class LoopHandler {
239 public:
240 LoopHandler(int max_cnt, const base::Closure& quit_closure)
241 : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
242
243 void OnUpdate(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38244 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09245 static int cnt = 0;
246 ++cnt;
247 if (cnt >= max_cnt_)
248 quit_closure_.Run();
249 }
250
251 private:
252 const int max_cnt_;
253 base::Closure quit_closure_;
254 };
255
sorin85953dc2016-03-10 00:32:48256 base::HistogramTester ht;
257
sorin7c717622015-05-26 19:59:09258 scoped_refptr<MockInstaller> installer(new MockInstaller());
259 EXPECT_CALL(*installer, Uninstall()).WillOnce(Return(true));
260
261 using update_client::jebg_hash;
262 using update_client::abag_hash;
263
264 const std::string id1 = "abagagagagagagagagagagagagagagag";
265 const std::string id2 = "jebgalgnebhfojomionfpkfelancnnkf";
266 std::vector<std::string> ids;
267 ids.push_back(id1);
268 ids.push_back(id2);
269
270 CrxComponent crx_component1;
271 crx_component1.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
pwnall15745b312016-08-19 21:45:29272 crx_component1.version = base::Version("1.0");
sorin7c717622015-05-26 19:59:09273 crx_component1.installer = installer;
274
275 CrxComponent crx_component2;
276 crx_component2.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29277 crx_component2.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09278 crx_component2.installer = installer;
279
280 // Quit after two update checks have fired.
281 LoopHandler loop_handler(2, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38282 EXPECT_CALL(update_client(), DoUpdate(ids, _))
sorin7c717622015-05-26 19:59:09283 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
284
285 EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
sorinecaad3e2015-11-13 19:15:52286 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09287
288 EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
289 EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
290
291 RunThreads();
sorin7c717622015-05-26 19:59:09292 EXPECT_TRUE(component_updater().UnregisterComponent(id1));
sorin85953dc2016-03-10 00:32:48293
294 ht.ExpectUniqueSample("ComponentUpdater.Calls", 1, 2);
295 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 2);
296 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 2);
sorin7c717622015-05-26 19:59:09297}
298
299// Tests that on-demand updates invoke UpdateClient::Install.
300TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
301 class LoopHandler {
302 public:
sorin7b8650522016-11-02 18:23:41303 explicit LoopHandler(int max_cnt) : max_cnt_(max_cnt) {}
sorin7c717622015-05-26 19:59:09304
sorin842703b2016-11-02 23:59:23305 void OnInstall(const std::string& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38306 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09307 static int cnt = 0;
308 ++cnt;
sorin4c520182016-08-19 17:27:44309 if (cnt >= max_cnt_) {
310 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58311 FROM_HERE,
312 base::BindOnce(&LoopHandler::Quit, base::Unretained(this)));
sorin4c520182016-08-19 17:27:44313 }
sorin7c717622015-05-26 19:59:09314 }
315
316 private:
Gabriel Charette53a9ef812017-07-26 12:36:23317 void Quit() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
sorin4c520182016-08-19 17:27:44318
sorin7c717622015-05-26 19:59:09319 const int max_cnt_;
sorin7c717622015-05-26 19:59:09320 };
321
sorin85953dc2016-03-10 00:32:48322 base::HistogramTester ht;
323
sorin7c717622015-05-26 19:59:09324 auto config = configurator();
325 config->SetInitialDelay(3600);
326
327 auto& cus = component_updater();
328
sorin4c520182016-08-19 17:27:44329 // Tests calling OnDemand for an unregistered component. This call results in
330 // an error, which is recorded by the OnDemandTester instance. Since the
331 // component was not registered, the call is ignored for UMA metrics.
332 OnDemandTester ondemand_tester_component_not_registered;
333 ondemand_tester_component_not_registered.OnDemand(
334 &cus, "ihfokbkgjpifnbbojhneepfflplebdkc");
sorin7c717622015-05-26 19:59:09335
sorin4c520182016-08-19 17:27:44336 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
sorin7c717622015-05-26 19:59:09337
338 using update_client::jebg_hash;
339 CrxComponent crx_component;
340 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29341 crx_component.version = base::Version("0.9");
sorin4c520182016-08-19 17:27:44342 crx_component.installer = new MockInstaller();
sorin7c717622015-05-26 19:59:09343
sorin4c520182016-08-19 17:27:44344 LoopHandler loop_handler(1);
Vladislav Kuzkokov12eca792017-10-20 12:45:38345 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09346 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52347 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09348
349 EXPECT_TRUE(cus.RegisterComponent(crx_component));
sorin4c520182016-08-19 17:27:44350 OnDemandTester ondemand_tester;
351 ondemand_tester.OnDemand(&cus, id);
sorin7c717622015-05-26 19:59:09352
sorin4c520182016-08-19 17:27:44353 base::RunLoop().Run();
354
sorin7b8650522016-11-02 18:23:41355 EXPECT_EQ(update_client::Error::INVALID_ARGUMENT,
356 ondemand_tester_component_not_registered.error());
357 EXPECT_EQ(update_client::Error::NONE, ondemand_tester.error());
sorin85953dc2016-03-10 00:32:48358
359 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
360 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
361 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09362}
363
364// Tests that throttling an update invokes UpdateClient::Install.
365TEST_F(ComponentUpdaterTest, MaybeThrottle) {
366 class LoopHandler {
367 public:
368 LoopHandler(int max_cnt, const base::Closure& quit_closure)
369 : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
370
sorin842703b2016-11-02 23:59:23371 void OnInstall(const std::string& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38372 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09373 static int cnt = 0;
374 ++cnt;
375 if (cnt >= max_cnt_)
376 quit_closure_.Run();
377 }
378
379 private:
380 const int max_cnt_;
381 base::Closure quit_closure_;
382 };
383
sorin85953dc2016-03-10 00:32:48384 base::HistogramTester ht;
385
sorin7c717622015-05-26 19:59:09386 auto config = configurator();
387 config->SetInitialDelay(3600);
388
389 scoped_refptr<MockInstaller> installer(new MockInstaller());
390
391 using update_client::jebg_hash;
392 CrxComponent crx_component;
393 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29394 crx_component.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09395 crx_component.installer = installer;
396
397 LoopHandler loop_handler(1, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38398 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09399 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52400 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09401
402 EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
403 component_updater().MaybeThrottle(
404 "jebgalgnebhfojomionfpkfelancnnkf",
405 base::Bind(&ComponentUpdaterTest::ReadyCallback));
406
407 RunThreads();
sorin85953dc2016-03-10 00:32:48408
409 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
410 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
411 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09412}
413
414} // namespace component_updater