1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/component_updater/component_updater_service.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/functional/bind.h"
17 #include "base/functional/callback_helpers.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/run_loop.h"
21 #include "base/task/sequenced_task_runner.h"
22 #include "base/test/metrics/histogram_tester.h"
23 #include "base/test/task_environment.h"
24 #include "base/values.h"
25 #include "components/component_updater/component_updater_service_internal.h"
26 #include "components/prefs/testing_pref_service.h"
27 #include "components/update_client/test_configurator.h"
28 #include "components/update_client/test_installer.h"
29 #include "components/update_client/update_client.h"
30 #include "components/update_client/update_client_errors.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 using Configurator = update_client::Configurator;
35 using Result = update_client::CrxInstaller::Result;
36 using TestConfigurator = update_client::TestConfigurator;
37 using UpdateClient = update_client::UpdateClient;
40 using ::testing::AnyNumber;
41 using ::testing::Invoke;
42 using ::testing::Mock;
43 using ::testing::Return;
44 using ::testing::Unused;
46 namespace component_updater {
48 class MockInstaller : public update_client::CrxInstaller {
50 MockInstaller() = default;
51 MOCK_METHOD1(OnUpdateError, void(int error));
53 void(const base::FilePath& unpack_path,
54 const std::string& public_key,
55 std::unique_ptr<InstallParams> install_params,
56 ProgressCallback progress_callback,
58 MOCK_METHOD2(GetInstalledFile,
59 bool(const std::string& file, base::FilePath* installed_file));
60 MOCK_METHOD0(Uninstall, bool());
63 ~MockInstaller() override = default;
66 class MockUpdateClient : public UpdateClient {
68 MockUpdateClient() = default;
70 MOCK_METHOD1(AddObserver, void(Observer* observer));
71 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
74 base::RepeatingClosure(const std::string& id,
75 CrxDataCallback crx_data_callback,
76 CrxStateChangeCallback crx_state_change_callback,
79 void(const std::vector<std::string>& ids,
80 CrxDataCallback crx_data_callback,
81 CrxStateChangeCallback crx_state_change_callback,
84 MOCK_METHOD5(CheckForUpdate,
85 void(const std::string& ids,
86 CrxDataCallback crx_data_callback,
87 CrxStateChangeCallback crx_state_change_callback,
90 MOCK_CONST_METHOD2(GetCrxUpdateState,
91 bool(const std::string& id, CrxUpdateItem* update_item));
92 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
93 MOCK_METHOD0(Stop, void());
94 MOCK_METHOD3(SendUninstallPing,
95 void(const CrxComponent& crx_component,
98 MOCK_METHOD5(SendInstallPing,
99 void(const CrxComponent& crx_component,
104 MOCK_METHOD2(SendRegistrationPing,
105 void(const CrxComponent& crx_component, Callback callback));
108 ~MockUpdateClient() override = default;
111 class MockServiceObserver : public ServiceObserver {
113 MockServiceObserver() = default;
114 ~MockServiceObserver() override = default;
116 MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
119 class MockUpdateScheduler : public UpdateScheduler {
121 MOCK_METHOD4(Schedule,
122 void(const base::TimeDelta& initial_delay,
123 const base::TimeDelta& delay,
124 const UserTask& user_task,
125 const OnStopTaskCallback& on_stop));
126 MOCK_METHOD0(Stop, void());
131 explicit LoopHandler(int max_cnt, base::OnceClosure quit_closure)
132 : max_cnt_(max_cnt), quit_closure_(std::move(quit_closure)) {}
134 base::RepeatingClosure OnInstall(const std::string&,
135 UpdateClient::CrxDataCallback,
136 UpdateClient::CrxStateChangeCallback,
138 Handle(std::move(callback));
139 return base::DoNothing();
142 void OnUpdate(const std::vector<std::string>&,
143 UpdateClient::CrxDataCallback,
144 UpdateClient::CrxStateChangeCallback,
147 EXPECT_FALSE(is_foreground);
148 Handle(std::move(callback));
152 void Handle(Callback callback) {
154 if (cnt_ >= max_cnt_) {
155 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
156 FROM_HERE, std::move(quit_closure_));
158 std::move(callback).Run(update_client::Error::NONE);
161 const int max_cnt_ = 0;
162 base::OnceClosure quit_closure_;
166 class ComponentUpdaterTest : public testing::Test {
168 ComponentUpdaterTest();
169 ComponentUpdaterTest(const ComponentUpdaterTest&) = delete;
170 ComponentUpdaterTest& operator=(const ComponentUpdaterTest&) = delete;
171 ~ComponentUpdaterTest() override;
173 // Makes the full path to a component updater test file.
174 const base::FilePath test_file(const char* file);
176 MockUpdateClient& update_client() { return *update_client_; }
177 ComponentUpdateService& component_updater() { return *component_updater_; }
178 scoped_refptr<TestConfigurator> configurator() const { return config_; }
179 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
180 MockUpdateScheduler& scheduler() { return *scheduler_; }
186 void RunUpdateTask(const UpdateScheduler::UserTask& user_task);
187 void Schedule(const base::TimeDelta& initial_delay,
188 const base::TimeDelta& delay,
189 const UpdateScheduler::UserTask& user_task,
190 const UpdateScheduler::OnStopTaskCallback& on_stop);
192 base::test::TaskEnvironment task_environment_;
193 base::RunLoop runloop_;
195 std::unique_ptr<TestingPrefServiceSimple> pref_ =
196 std::make_unique<TestingPrefServiceSimple>();
197 scoped_refptr<TestConfigurator> config_ =
198 base::MakeRefCounted<TestConfigurator>(pref_.get());
199 scoped_refptr<MockUpdateClient> update_client_ =
200 base::MakeRefCounted<MockUpdateClient>();
201 std::unique_ptr<ComponentUpdateService> component_updater_;
202 raw_ptr<MockUpdateScheduler> scheduler_;
205 class OnDemandTester {
207 void OnDemand(ComponentUpdateService* cus,
208 const std::string& id,
209 OnDemandUpdater::Priority priority);
210 update_client::Error error() const { return error_; }
213 void OnDemandComplete(update_client::Error error);
215 update_client::Error error_ = update_client::Error::NONE;
218 void OnDemandTester::OnDemand(ComponentUpdateService* cus,
219 const std::string& id,
220 OnDemandUpdater::Priority priority) {
221 cus->GetOnDemandUpdater().OnDemandUpdate(
223 base::BindOnce(&OnDemandTester::OnDemandComplete,
224 base::Unretained(this)));
227 void OnDemandTester::OnDemandComplete(update_client::Error error) {
231 std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
232 scoped_refptr<Configurator> config) {
234 return std::make_unique<CrxUpdateService>(
235 config, std::make_unique<MockUpdateScheduler>(),
236 base::MakeRefCounted<MockUpdateClient>(), "");
239 ComponentUpdaterTest::ComponentUpdaterTest() {
240 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
241 auto scheduler = std::make_unique<MockUpdateScheduler>();
242 scheduler_ = scheduler.get();
243 ON_CALL(*scheduler_, Schedule(_, _, _, _))
244 .WillByDefault(Invoke(this, &ComponentUpdaterTest::Schedule));
245 component_updater_ = std::make_unique<CrxUpdateService>(
246 config_, std::move(scheduler), update_client_, "");
247 RegisterComponentUpdateServicePrefs(pref_->registry());
250 ComponentUpdaterTest::~ComponentUpdaterTest() {
251 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
254 void ComponentUpdaterTest::RunThreads() {
258 void ComponentUpdaterTest::RunUpdateTask(
259 const UpdateScheduler::UserTask& user_task) {
260 task_environment_.GetMainThreadTaskRunner()->PostTask(
261 FROM_HERE, base::BindRepeating(
262 [](const UpdateScheduler::UserTask& user_task,
263 ComponentUpdaterTest* test) {
264 user_task.Run(base::BindOnce(
265 [](const UpdateScheduler::UserTask& user_task,
266 ComponentUpdaterTest* test) {
267 test->RunUpdateTask(user_task);
269 user_task, base::Unretained(test)));
271 user_task, base::Unretained(this)));
274 void ComponentUpdaterTest::Schedule(
275 const base::TimeDelta& initial_delay,
276 const base::TimeDelta& delay,
277 const UpdateScheduler::UserTask& user_task,
278 const UpdateScheduler::OnStopTaskCallback& on_stop) {
279 RunUpdateTask(user_task);
282 TEST_F(ComponentUpdaterTest, AddObserver) {
283 MockServiceObserver observer;
284 EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
285 EXPECT_CALL(update_client(), Stop()).Times(1);
286 EXPECT_CALL(scheduler(), Stop()).Times(1);
287 component_updater().AddObserver(&observer);
290 TEST_F(ComponentUpdaterTest, RemoveObserver) {
291 MockServiceObserver observer;
292 EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
293 EXPECT_CALL(update_client(), Stop()).Times(1);
294 EXPECT_CALL(scheduler(), Stop()).Times(1);
295 component_updater().RemoveObserver(&observer);
298 // Tests that UpdateClient::Update is called by the timer loop when
299 // components are registered, and the component update starts.
300 // Also tests that Uninstall is called when a component is unregistered.
301 TEST_F(ComponentUpdaterTest, RegisterComponent) {
302 base::HistogramTester ht;
304 scoped_refptr<MockInstaller> installer =
305 base::MakeRefCounted<MockInstaller>();
306 EXPECT_CALL(*installer, Uninstall()).WillOnce(Return(true));
308 using update_client::jebg_hash;
309 using update_client::abag_hash;
311 const std::string id1 = "abagagagagagagagagagagagagagagag";
312 const std::string id2 = "jebgalgnebhfojomionfpkfelancnnkf";
313 std::vector<std::string> ids;
317 std::vector<uint8_t> hash;
318 hash.assign(std::begin(abag_hash), std::end(abag_hash));
319 ComponentRegistration component1(id1, {}, hash, base::Version("1.0"), {}, {},
320 nullptr, installer, false, true);
322 hash.assign(std::begin(jebg_hash), std::end(jebg_hash));
323 ComponentRegistration component2(id2, {}, hash, base::Version("0.9"), {}, {},
324 nullptr, installer, false, true);
326 // Quit after two update checks have fired.
327 LoopHandler loop_handler(2, quit_closure());
328 EXPECT_CALL(update_client(), Update(_, _, _, _, _))
329 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
331 EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
332 EXPECT_CALL(update_client(), Stop()).Times(1);
333 EXPECT_CALL(scheduler(), Schedule(_, _, _, _)).Times(1);
334 EXPECT_CALL(scheduler(), Stop()).Times(1);
336 EXPECT_TRUE(component_updater().RegisterComponent(component1));
337 EXPECT_TRUE(component_updater().RegisterComponent(component2));
340 EXPECT_TRUE(component_updater().UnregisterComponent(id1));
342 ht.ExpectUniqueSample("ComponentUpdater.Calls", 1, 2);
343 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 2);
344 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 2);
347 // Tests that on-demand updates invoke UpdateClient::Install.
348 TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
349 base::HistogramTester ht;
351 // Don't run periodic update task.
352 ON_CALL(scheduler(), Schedule(_, _, _, _)).WillByDefault(Return());
354 auto& cus = component_updater();
356 // Tests calling OnDemand for an unregistered component. This call results in
357 // an error, which is recorded by the OnDemandTester instance. Since the
358 // component was not registered, the call is ignored for UMA metrics.
359 OnDemandTester ondemand_tester_component_not_registered;
360 ondemand_tester_component_not_registered.OnDemand(
361 &cus, "ihfokbkgjpifnbbojhneepfflplebdkc",
362 OnDemandUpdater::Priority::FOREGROUND);
364 // Register two components, then call |OnDemand| for each component, with
365 // foreground and background priorities. Expect calls to |Schedule| because
366 // components have registered, calls to |Install| and |Update| corresponding
367 // to each |OnDemand| invocation, and calls to |Stop| when the mocks are
369 LoopHandler loop_handler(2, quit_closure());
370 EXPECT_CALL(scheduler(), Schedule(_, _, _, _)).Times(1);
371 EXPECT_CALL(update_client(), Install(_, _, _, _))
372 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
373 EXPECT_CALL(update_client(), Update(_, _, _, _, _))
374 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnUpdate));
375 EXPECT_CALL(update_client(), Stop()).Times(1);
376 EXPECT_CALL(scheduler(), Stop()).Times(1);
379 using update_client::jebg_hash;
380 std::vector<uint8_t> hash;
381 hash.assign(std::begin(jebg_hash), std::end(jebg_hash));
382 EXPECT_TRUE(cus.RegisterComponent(ComponentRegistration(
383 "jebgalgnebhfojomionfpkfelancnnkf", {}, hash, base::Version("0.9"), {},
384 {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true)));
387 using update_client::abag_hash;
388 std::vector<uint8_t> hash;
389 hash.assign(std::begin(abag_hash), std::end(abag_hash));
390 EXPECT_TRUE(cus.RegisterComponent(ComponentRegistration(
391 "abagagagagagagagagagagagagagagag", {}, hash, base::Version("0.9"), {},
392 {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true)));
395 OnDemandTester ondemand_tester;
396 ondemand_tester.OnDemand(&cus, "jebgalgnebhfojomionfpkfelancnnkf",
397 OnDemandUpdater::Priority::FOREGROUND);
398 ondemand_tester.OnDemand(&cus, "abagagagagagagagagagagagagagagag",
399 OnDemandUpdater::Priority::BACKGROUND);
402 EXPECT_EQ(update_client::Error::INVALID_ARGUMENT,
403 ondemand_tester_component_not_registered.error());
404 EXPECT_EQ(update_client::Error::NONE, ondemand_tester.error());
406 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 2);
407 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 2);
408 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 2);
411 // Tests that throttling an update invokes UpdateClient::Install.
412 TEST_F(ComponentUpdaterTest, MaybeThrottle) {
413 base::HistogramTester ht;
415 // Don't run periodic update task.
416 ON_CALL(scheduler(), Schedule(_, _, _, _)).WillByDefault(Return());
418 using update_client::jebg_hash;
419 std::vector<uint8_t> hash;
420 hash.assign(std::begin(jebg_hash), std::end(jebg_hash));
422 LoopHandler loop_handler(1, quit_closure());
423 EXPECT_CALL(update_client(), Install(_, _, _, _))
424 .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
425 EXPECT_CALL(update_client(), Stop()).Times(1);
426 EXPECT_CALL(scheduler(), Schedule(_, _, _, _)).Times(1);
427 EXPECT_CALL(scheduler(), Stop()).Times(1);
429 EXPECT_TRUE(component_updater().RegisterComponent(ComponentRegistration(
430 "jebgalgnebhfojomionfpkfelancnnkf", {}, hash, base::Version("0.9"), {},
431 {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true)));
432 component_updater().MaybeThrottle("jebgalgnebhfojomionfpkfelancnnkf",
437 ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
438 ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
439 ht.ExpectTotalCount("ComponentUpdater.UpdateCompleteTime", 1);
442 } // namespace component_updater