blob: 4671c74168bf39b388650356fbf8ef6f089367f7 [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 Jianu7aa6d1f2017-10-13 20:29:2951 MOCK_METHOD2(Install,
52 void(const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:4153 const update_client::CrxInstaller::Callback& callback));
sorin7c717622015-05-26 19:59:0954 MOCK_METHOD2(GetInstalledFile,
55 bool(const std::string& file, base::FilePath* installed_file));
56 MOCK_METHOD0(Uninstall, bool());
57
58 private:
59 ~MockInstaller() override;
60};
61
62class MockUpdateClient : public UpdateClient {
63 public:
64 MockUpdateClient();
Vladislav Kuzkokov12eca792017-10-20 12:45:3865
66 void Install(const std::string& id,
67 const CrxDataCallback& crx_data_callback,
68 Callback callback) override {
69 DoInstall(id, crx_data_callback);
70 std::move(callback).Run(update_client::Error::NONE);
71 }
72
73 void Update(const std::vector<std::string>& ids,
74 const CrxDataCallback& crx_data_callback,
75 Callback callback) override {
76 DoUpdate(ids, crx_data_callback);
77 std::move(callback).Run(update_client::Error::NONE);
78 }
79
80 void SendUninstallPing(const std::string& id,
81 const base::Version& version,
82 int reason,
83 Callback callback) {
84 DoSendUninstallPing(id, version, reason);
85 std::move(callback).Run(update_client::Error::NONE);
86 }
87
sorin7c717622015-05-26 19:59:0988 MOCK_METHOD1(AddObserver, void(Observer* observer));
89 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
Vladislav Kuzkokov12eca792017-10-20 12:45:3890 MOCK_METHOD2(DoInstall,
sorin7c717622015-05-26 19:59:0991 void(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:3892 const CrxDataCallback& crx_data_callback));
93 MOCK_METHOD2(DoUpdate,
sorin7c717622015-05-26 19:59:0994 void(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:3895 const CrxDataCallback& crx_data_callback));
sorin7c717622015-05-26 19:59:0996 MOCK_CONST_METHOD2(GetCrxUpdateState,
97 bool(const std::string& id, CrxUpdateItem* update_item));
98 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
sorinecaad3e2015-11-13 19:15:5299 MOCK_METHOD0(Stop, void());
Vladislav Kuzkokov12eca792017-10-20 12:45:38100 MOCK_METHOD3(DoSendUninstallPing,
sorin8037ac8c2017-04-19 16:28:00101 void(const std::string& id,
102 const base::Version& version,
Vladislav Kuzkokov12eca792017-10-20 12:45:38103 int reason));
sorin7c717622015-05-26 19:59:09104
105 private:
106 ~MockUpdateClient() override;
107};
108
109class MockServiceObserver : public ServiceObserver {
110 public:
111 MockServiceObserver();
112 ~MockServiceObserver() override;
113
114 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
115};
116
117class ComponentUpdaterTest : public testing::Test {
118 public:
119 ComponentUpdaterTest();
120 ~ComponentUpdaterTest() override;
121
122 void SetUp() override;
123
124 void TearDown() override;
125
126 // Makes the full path to a component updater test file.
127 const base::FilePath test_file(const char* file);
128
129 MockUpdateClient& update_client() { return *update_client_; }
130 ComponentUpdateService& component_updater() { return *component_updater_; }
131 scoped_refptr<TestConfigurator> configurator() const { return config_; }
132 base::Closure quit_closure() const { return quit_closure_; }
133 static void ReadyCallback() {}
134
135 protected:
136 void RunThreads();
137
138 private:
fdoraydc4d9942017-05-12 20:13:50139 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin7c717622015-05-26 19:59:09140 base::RunLoop runloop_;
Sorin Jianucc048f892017-07-26 02:05:54141 const base::Closure quit_closure_ = runloop_.QuitClosure();
sorin7c717622015-05-26 19:59:09142
Sorin Jianucc048f892017-07-26 02:05:54143 scoped_refptr<TestConfigurator> config_ =
144 base::MakeRefCounted<TestConfigurator>();
145 scoped_refptr<MockUpdateClient> update_client_ =
146 base::MakeRefCounted<MockUpdateClient>();
dchenga0ee5fb82016-04-26 02:46:55147 std::unique_ptr<ComponentUpdateService> component_updater_;
sorin7c717622015-05-26 19:59:09148
149 DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterTest);
150};
151
152class OnDemandTester {
153 public:
sorin4c520182016-08-19 17:27:44154 void OnDemand(ComponentUpdateService* cus, const std::string& id);
sorin7b8650522016-11-02 18:23:41155 update_client::Error error() const { return error_; }
sorin4c520182016-08-19 17:27:44156
157 private:
sorin7b8650522016-11-02 18:23:41158 void OnDemandComplete(update_client::Error error);
sorin4c520182016-08-19 17:27:44159
sorin7b8650522016-11-02 18:23:41160 update_client::Error error_ = update_client::Error::NONE;
sorin7c717622015-05-26 19:59:09161};
162
163MockInstaller::MockInstaller() {
164}
165
166MockInstaller::~MockInstaller() {
167}
168
169MockUpdateClient::MockUpdateClient() {
170}
171
172MockUpdateClient::~MockUpdateClient() {
173}
174
175MockServiceObserver::MockServiceObserver() {
176}
177
178MockServiceObserver::~MockServiceObserver() {
179}
180
sorin4c520182016-08-19 17:27:44181void OnDemandTester::OnDemand(ComponentUpdateService* cus,
sorin7c717622015-05-26 19:59:09182 const std::string& id) {
sorin4c520182016-08-19 17:27:44183 cus->GetOnDemandUpdater().OnDemandUpdate(
184 id,
185 base::Bind(&OnDemandTester::OnDemandComplete, base::Unretained(this)));
186}
187
sorin7b8650522016-11-02 18:23:41188void OnDemandTester::OnDemandComplete(update_client::Error error) {
sorin4c520182016-08-19 17:27:44189 error_ = error;
sorin7c717622015-05-26 19:59:09190}
191
dchenga0ee5fb82016-04-26 02:46:55192std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
sorin7c717622015-05-26 19:59:09193 const scoped_refptr<Configurator>& config) {
194 DCHECK(config);
ricea85ec57952016-08-31 09:34:10195 return base::MakeUnique<CrxUpdateService>(config, new MockUpdateClient());
sorin7c717622015-05-26 19:59:09196}
197
Sorin Jianucc048f892017-07-26 02:05:54198ComponentUpdaterTest::ComponentUpdaterTest() {
sorin7c717622015-05-26 19:59:09199 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
Sorin Jianuebd652462017-07-23 02:00:58200 component_updater_ =
201 base::MakeUnique<CrxUpdateService>(config_, update_client_);
sorin7c717622015-05-26 19:59:09202}
203
204ComponentUpdaterTest::~ComponentUpdaterTest() {
205 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
sorin7c717622015-05-26 19:59:09206 component_updater_.reset();
207}
208
209void ComponentUpdaterTest::SetUp() {
210}
211
212void ComponentUpdaterTest::TearDown() {
213}
214
215void ComponentUpdaterTest::RunThreads() {
216 runloop_.Run();
217}
218
219TEST_F(ComponentUpdaterTest, AddObserver) {
220 MockServiceObserver observer;
221 EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52222 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09223 component_updater().AddObserver(&observer);
224}
225
226TEST_F(ComponentUpdaterTest, RemoveObserver) {
227 MockServiceObserver observer;
228 EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
sorinecaad3e2015-11-13 19:15:52229 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09230 component_updater().RemoveObserver(&observer);
231}
232
233// Tests that UpdateClient::Update is called by the timer loop when
234// components are registered, and the component update starts.
235// Also tests that Uninstall is called when a component is unregistered.
236TEST_F(ComponentUpdaterTest, RegisterComponent) {
237 class LoopHandler {
238 public:
239 LoopHandler(int max_cnt, const base::Closure& quit_closure)
240 : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
241
242 void OnUpdate(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38243 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09244 static int cnt = 0;
245 ++cnt;
246 if (cnt >= max_cnt_)
247 quit_closure_.Run();
248 }
249
250 private:
251 const int max_cnt_;
252 base::Closure quit_closure_;
253 };
254
sorin85953dc2016-03-10 00:32:48255 base::HistogramTester ht;
256
sorin7c717622015-05-26 19:59:09257 scoped_refptr<MockInstaller> installer(new MockInstaller());
258 EXPECT_CALL(*installer, Uninstall()).WillOnce(Return(true));
259
260 using update_client::jebg_hash;
261 using update_client::abag_hash;
262
263 const std::string id1 = "abagagagagagagagagagagagagagagag";
264 const std::string id2 = "jebgalgnebhfojomionfpkfelancnnkf";
265 std::vector<std::string> ids;
266 ids.push_back(id1);
267 ids.push_back(id2);
268
269 CrxComponent crx_component1;
270 crx_component1.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
pwnall15745b312016-08-19 21:45:29271 crx_component1.version = base::Version("1.0");
sorin7c717622015-05-26 19:59:09272 crx_component1.installer = installer;
273
274 CrxComponent crx_component2;
275 crx_component2.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29276 crx_component2.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09277 crx_component2.installer = installer;
278
279 // Quit after two update checks have fired.
280 LoopHandler loop_handler(2, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38281 EXPECT_CALL(update_client(), DoUpdate(ids, _))
sorin7c717622015-05-26 19:59:09282 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
283
284 EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
sorinecaad3e2015-11-13 19:15:52285 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09286
287 EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
288 EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
289
290 RunThreads();
sorin7c717622015-05-26 19:59:09291 EXPECT_TRUE(component_updater().UnregisterComponent(id1));
sorin85953dc2016-03-10 00:32:48292
293 ht.ExpectUniqueSample("ComponentUpdater.Calls", 1, 2);
294 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 2);
295 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 2);
sorin7c717622015-05-26 19:59:09296}
297
298// Tests that on-demand updates invoke UpdateClient::Install.
299TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
300 class LoopHandler {
301 public:
sorin7b8650522016-11-02 18:23:41302 explicit LoopHandler(int max_cnt) : max_cnt_(max_cnt) {}
sorin7c717622015-05-26 19:59:09303
sorin842703b2016-11-02 23:59:23304 void OnInstall(const std::string& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38305 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09306 static int cnt = 0;
307 ++cnt;
sorin4c520182016-08-19 17:27:44308 if (cnt >= max_cnt_) {
309 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58310 FROM_HERE,
311 base::BindOnce(&LoopHandler::Quit, base::Unretained(this)));
sorin4c520182016-08-19 17:27:44312 }
sorin7c717622015-05-26 19:59:09313 }
314
315 private:
Gabriel Charette53a9ef812017-07-26 12:36:23316 void Quit() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
sorin4c520182016-08-19 17:27:44317
sorin7c717622015-05-26 19:59:09318 const int max_cnt_;
sorin7c717622015-05-26 19:59:09319 };
320
sorin85953dc2016-03-10 00:32:48321 base::HistogramTester ht;
322
sorin7c717622015-05-26 19:59:09323 auto config = configurator();
324 config->SetInitialDelay(3600);
325
326 auto& cus = component_updater();
327
sorin4c520182016-08-19 17:27:44328 // Tests calling OnDemand for an unregistered component. This call results in
329 // an error, which is recorded by the OnDemandTester instance. Since the
330 // component was not registered, the call is ignored for UMA metrics.
331 OnDemandTester ondemand_tester_component_not_registered;
332 ondemand_tester_component_not_registered.OnDemand(
333 &cus, "ihfokbkgjpifnbbojhneepfflplebdkc");
sorin7c717622015-05-26 19:59:09334
sorin4c520182016-08-19 17:27:44335 const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
sorin7c717622015-05-26 19:59:09336
337 using update_client::jebg_hash;
338 CrxComponent crx_component;
339 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29340 crx_component.version = base::Version("0.9");
sorin4c520182016-08-19 17:27:44341 crx_component.installer = new MockInstaller();
sorin7c717622015-05-26 19:59:09342
sorin4c520182016-08-19 17:27:44343 LoopHandler loop_handler(1);
Vladislav Kuzkokov12eca792017-10-20 12:45:38344 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09345 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52346 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09347
348 EXPECT_TRUE(cus.RegisterComponent(crx_component));
sorin4c520182016-08-19 17:27:44349 OnDemandTester ondemand_tester;
350 ondemand_tester.OnDemand(&cus, id);
sorin7c717622015-05-26 19:59:09351
sorin4c520182016-08-19 17:27:44352 base::RunLoop().Run();
353
sorin7b8650522016-11-02 18:23:41354 EXPECT_EQ(update_client::Error::INVALID_ARGUMENT,
355 ondemand_tester_component_not_registered.error());
356 EXPECT_EQ(update_client::Error::NONE, ondemand_tester.error());
sorin85953dc2016-03-10 00:32:48357
358 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
359 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
360 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09361}
362
363// Tests that throttling an update invokes UpdateClient::Install.
364TEST_F(ComponentUpdaterTest, MaybeThrottle) {
365 class LoopHandler {
366 public:
367 LoopHandler(int max_cnt, const base::Closure& quit_closure)
368 : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
369
sorin842703b2016-11-02 23:59:23370 void OnInstall(const std::string& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38371 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin7c717622015-05-26 19:59:09372 static int cnt = 0;
373 ++cnt;
374 if (cnt >= max_cnt_)
375 quit_closure_.Run();
376 }
377
378 private:
379 const int max_cnt_;
380 base::Closure quit_closure_;
381 };
382
sorin85953dc2016-03-10 00:32:48383 base::HistogramTester ht;
384
sorin7c717622015-05-26 19:59:09385 auto config = configurator();
386 config->SetInitialDelay(3600);
387
388 scoped_refptr<MockInstaller> installer(new MockInstaller());
389
390 using update_client::jebg_hash;
391 CrxComponent crx_component;
392 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
pwnall15745b312016-08-19 21:45:29393 crx_component.version = base::Version("0.9");
sorin7c717622015-05-26 19:59:09394 crx_component.installer = installer;
395
396 LoopHandler loop_handler(1, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38397 EXPECT_CALL(update_client(), DoInstall("jebgalgnebhfojomionfpkfelancnnkf", _))
sorin7c717622015-05-26 19:59:09398 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
sorinecaad3e2015-11-13 19:15:52399 EXPECT_CALL(update_client(), Stop()).Times(1);
sorin7c717622015-05-26 19:59:09400
401 EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
402 component_updater().MaybeThrottle(
403 "jebgalgnebhfojomionfpkfelancnnkf",
404 base::Bind(&ComponentUpdaterTest::ReadyCallback));
405
406 RunThreads();
sorin85953dc2016-03-10 00:32:48407
408 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
409 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
410 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
sorin7c717622015-05-26 19:59:09411}
412
413} // namespace component_updater