blob: 959ec1faad2bae1ab9cc25f23687a8ff8b233ecc [file] [log] [blame]
sorin6a57db92016-06-27 22:28:151// Copyright 2016 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
5#include <iterator>
Gyuyoung Kim6afb5082018-01-19 13:35:576#include <memory>
sorin6a57db92016-06-27 22:28:157#include <string>
waffles77255cc2016-08-02 17:25:128#include <utility>
sorin6a57db92016-06-27 22:28:159#include <vector>
10
Sorin Jianuf40ab4b32017-10-06 22:53:4111#include "base/bind.h"
sorin6a57db92016-06-27 22:28:1512#include "base/callback.h"
Sorin Jianu316232a2017-05-26 20:22:3013#include "base/files/file_path.h"
14#include "base/files/file_util.h"
sorin6a57db92016-06-27 22:28:1515#include "base/macros.h"
sorin6a57db92016-06-27 22:28:1516#include "base/memory/ref_counted.h"
Sorin Jianu316232a2017-05-26 20:22:3017#include "base/path_service.h"
sorin6a57db92016-06-27 22:28:1518#include "base/run_loop.h"
fdorayb26583c2017-05-16 18:47:0119#include "base/task_scheduler/post_task.h"
Sorin Jianu316232a2017-05-26 20:22:3020#include "base/test/scoped_path_override.h"
fdorayb26583c2017-05-16 18:47:0121#include "base/test/scoped_task_environment.h"
22#include "base/threading/thread_task_runner_handle.h"
sorin6a57db92016-06-27 22:28:1523#include "base/version.h"
Sorin Jianu08f92b3c2017-09-25 16:17:1224#include "components/component_updater/component_installer.h"
Sorin Jianu316232a2017-05-26 20:22:3025#include "components/component_updater/component_updater_paths.h"
sorin6a57db92016-06-27 22:28:1526#include "components/component_updater/component_updater_service.h"
27#include "components/component_updater/component_updater_service_internal.h"
Sorin Jianu316232a2017-05-26 20:22:3028#include "components/update_client/component_unpacker.h"
sorin6a57db92016-06-27 22:28:1529#include "components/update_client/crx_update_item.h"
30#include "components/update_client/test_configurator.h"
31#include "components/update_client/update_client.h"
sorin7b8650522016-11-02 18:23:4132#include "components/update_client/update_client_errors.h"
Jay Civelli29f9b942017-11-08 20:07:2633#include "services/service_manager/public/cpp/connector.h"
sorin6a57db92016-06-27 22:28:1534#include "testing/gmock/include/gmock/gmock.h"
35#include "testing/gtest/include/gtest/gtest.h"
36
Sorin Jianu316232a2017-05-26 20:22:3037using ComponentUnpacker = update_client::ComponentUnpacker;
sorin6a57db92016-06-27 22:28:1538using Configurator = update_client::Configurator;
39using CrxUpdateItem = update_client::CrxUpdateItem;
40using TestConfigurator = update_client::TestConfigurator;
41using UpdateClient = update_client::UpdateClient;
42
43using ::testing::_;
44using ::testing::Invoke;
45
46namespace component_updater {
47
48namespace {
49
50// This hash corresponds to jebgalgnebhfojomionfpkfelancnnkf.crx.
51const uint8_t kSha256Hash[] = {0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec,
52 0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5,
53 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4,
54 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40};
55
Sorin Jianu316232a2017-05-26 20:22:3056constexpr base::FilePath::CharType relative_install_dir[] =
57 FILE_PATH_LITERAL("fake");
58
59base::FilePath test_file(const char* file) {
60 base::FilePath path;
61 PathService::Get(base::DIR_SOURCE_ROOT, &path);
62 return path.AppendASCII("components")
63 .AppendASCII("test")
64 .AppendASCII("data")
65 .AppendASCII("update_client")
66 .AppendASCII(file);
67}
68
sorin6a57db92016-06-27 22:28:1569class MockUpdateClient : public UpdateClient {
70 public:
sorin2adb2ca2016-06-29 01:44:3571 MockUpdateClient() {}
Vladislav Kuzkokov12eca792017-10-20 12:45:3872
73 void Install(const std::string& id,
Sorin Jianua8ef73d2017-11-02 16:55:1774 CrxDataCallback crx_data_callback,
Vladislav Kuzkokov12eca792017-10-20 12:45:3875 Callback callback) {
Sorin Jianua8ef73d2017-11-02 16:55:1776 DoInstall(id, std::move(crx_data_callback));
Vladislav Kuzkokov12eca792017-10-20 12:45:3877 std::move(callback).Run(update_client::Error::NONE);
78 }
79
80 void Update(const std::vector<std::string>& ids,
Sorin Jianua8ef73d2017-11-02 16:55:1781 CrxDataCallback crx_data_callback,
Sorin Jianub41a592a2018-03-02 16:30:2782 bool is_foreground,
Vladislav Kuzkokov12eca792017-10-20 12:45:3883 Callback callback) {
Sorin Jianua8ef73d2017-11-02 16:55:1784 DoUpdate(ids, std::move(crx_data_callback));
Vladislav Kuzkokov12eca792017-10-20 12:45:3885 std::move(callback).Run(update_client::Error::NONE);
86 }
87
88 void SendUninstallPing(const std::string& id,
89 const base::Version& version,
90 int reason,
91 Callback callback) {
92 DoSendUninstallPing(id, version, reason);
93 std::move(callback).Run(update_client::Error::NONE);
94 }
95
sorin6a57db92016-06-27 22:28:1596 MOCK_METHOD1(AddObserver, void(Observer* observer));
97 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
Vladislav Kuzkokov12eca792017-10-20 12:45:3898 MOCK_METHOD2(DoInstall,
sorin6a57db92016-06-27 22:28:1599 void(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:38100 const CrxDataCallback& crx_data_callback));
101 MOCK_METHOD2(DoUpdate,
sorin6a57db92016-06-27 22:28:15102 void(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38103 const CrxDataCallback& crx_data_callback));
sorin6a57db92016-06-27 22:28:15104 MOCK_CONST_METHOD2(GetCrxUpdateState,
105 bool(const std::string& id, CrxUpdateItem* update_item));
106 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
107 MOCK_METHOD0(Stop, void());
Vladislav Kuzkokov12eca792017-10-20 12:45:38108 MOCK_METHOD3(DoSendUninstallPing,
sorin8037ac8c2017-04-19 16:28:00109 void(const std::string& id,
110 const base::Version& version,
Vladislav Kuzkokov12eca792017-10-20 12:45:38111 int reason));
sorin6a57db92016-06-27 22:28:15112
113 private:
sorin2adb2ca2016-06-29 01:44:35114 ~MockUpdateClient() override {}
sorin6a57db92016-06-27 22:28:15115};
116
Sorin Jianua8926bf2018-03-09 21:02:53117class MockInstallerPolicy : public ComponentInstallerPolicy {
sorin6a57db92016-06-27 22:28:15118 public:
Sorin Jianua8926bf2018-03-09 21:02:53119 MockInstallerPolicy() {}
120 ~MockInstallerPolicy() override {}
sorin6a57db92016-06-27 22:28:15121
122 bool VerifyInstallation(const base::DictionaryValue& manifest,
123 const base::FilePath& dir) const override {
124 return true;
125 }
126
sorin3574ef92016-08-03 16:46:01127 bool SupportsGroupPolicyEnabledComponentUpdates() const override {
sorin098a4a72016-08-30 04:43:24128 return true;
sorin3574ef92016-08-03 16:46:01129 }
sorin6a57db92016-06-27 22:28:15130
131 bool RequiresNetworkEncryption() const override { return true; }
132
sorin2892f7212016-11-07 18:59:43133 update_client::CrxInstaller::Result OnCustomInstall(
134 const base::DictionaryValue& manifest,
135 const base::FilePath& install_dir) override {
136 return update_client::CrxInstaller::Result(0);
sorin6a57db92016-06-27 22:28:15137 }
138
Xiaochu Liu1e306a32017-11-08 18:57:34139 void OnCustomUninstall() override {}
140
sorin6a57db92016-06-27 22:28:15141 void ComponentReady(
142 const base::Version& version,
143 const base::FilePath& install_dir,
144 std::unique_ptr<base::DictionaryValue> manifest) override {}
145
146 base::FilePath GetRelativeInstallDir() const override {
Sorin Jianu316232a2017-05-26 20:22:30147 return base::FilePath(relative_install_dir);
sorin6a57db92016-06-27 22:28:15148 }
149
150 void GetHash(std::vector<uint8_t>* hash) const override { GetPkHash(hash); }
151
152 std::string GetName() const override { return "fake name"; }
153
sorin2adb2ca2016-06-29 01:44:35154 update_client::InstallerAttributes GetInstallerAttributes() const override {
155 update_client::InstallerAttributes installer_attributes;
156 installer_attributes["ap"] = "fake-ap";
157 installer_attributes["is-enterprise"] = "1";
158 return installer_attributes;
159 }
sorin6a57db92016-06-27 22:28:15160
waffles77255cc2016-08-02 17:25:12161 std::vector<std::string> GetMimeTypes() const override {
162 return std::vector<std::string>();
163 }
164
sorin6a57db92016-06-27 22:28:15165 private:
166 static void GetPkHash(std::vector<uint8_t>* hash) {
167 hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
168 }
169};
170
Sorin Jianu08f92b3c2017-09-25 16:17:12171class ComponentInstallerTest : public testing::Test {
sorin6a57db92016-06-27 22:28:15172 public:
Sorin Jianu08f92b3c2017-09-25 16:17:12173 ComponentInstallerTest();
174 ~ComponentInstallerTest() override;
sorin6a57db92016-06-27 22:28:15175
176 MockUpdateClient& update_client() { return *update_client_; }
177 ComponentUpdateService* component_updater() {
178 return component_updater_.get();
179 }
180 scoped_refptr<TestConfigurator> configurator() const { return config_; }
Sorin Jianua8ef73d2017-11-02 16:55:17181 base::OnceClosure quit_closure() { return runloop_.QuitClosure(); }
sorin6a57db92016-06-27 22:28:15182
183 protected:
184 void RunThreads();
Sorin Jianu316232a2017-05-26 20:22:30185 void Unpack(const base::FilePath& crx_path);
186 ComponentUnpacker::Result result() const { return result_; }
sorin6a57db92016-06-27 22:28:15187
Sorin Jianuf40ab4b32017-10-06 22:53:41188 base::test::ScopedTaskEnvironment scoped_task_environment_;
189
sorin6a57db92016-06-27 22:28:15190 private:
Sorin Jianu316232a2017-05-26 20:22:30191 void UnpackComplete(const ComponentUnpacker::Result& result);
192
Sorin Jianu316232a2017-05-26 20:22:30193 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_ =
194 base::ThreadTaskRunnerHandle::Get();
sorin6a57db92016-06-27 22:28:15195 base::RunLoop runloop_;
sorin6a57db92016-06-27 22:28:15196
Sorin Jianucc048f892017-07-26 02:05:54197 scoped_refptr<TestConfigurator> config_ =
198 base::MakeRefCounted<TestConfigurator>();
199 scoped_refptr<MockUpdateClient> update_client_ =
200 base::MakeRefCounted<MockUpdateClient>();
sorin6a57db92016-06-27 22:28:15201 std::unique_ptr<ComponentUpdateService> component_updater_;
Sorin Jianu316232a2017-05-26 20:22:30202 ComponentUnpacker::Result result_;
sorin6a57db92016-06-27 22:28:15203};
204
Sorin Jianu08f92b3c2017-09-25 16:17:12205ComponentInstallerTest::ComponentInstallerTest() {
sorin6a57db92016-06-27 22:28:15206 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
Sorin Jianu316232a2017-05-26 20:22:30207 component_updater_ =
Gyuyoung Kim6afb5082018-01-19 13:35:57208 std::make_unique<CrxUpdateService>(config_, update_client_);
sorin6a57db92016-06-27 22:28:15209}
210
Sorin Jianu08f92b3c2017-09-25 16:17:12211ComponentInstallerTest::~ComponentInstallerTest() {
sorin6a57db92016-06-27 22:28:15212 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
213 component_updater_.reset();
214}
215
Sorin Jianu08f92b3c2017-09-25 16:17:12216void ComponentInstallerTest::RunThreads() {
sorin6a57db92016-06-27 22:28:15217 runloop_.Run();
218}
219
Sorin Jianu08f92b3c2017-09-25 16:17:12220void ComponentInstallerTest::Unpack(const base::FilePath& crx_path) {
Joshua Pawlicki6d764422018-02-21 15:23:10221 auto config = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu316232a2017-05-26 20:22:30222 auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
223 std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
Joshua Pawlicki6d764422018-02-21 15:23:10224 crx_path, nullptr, config->CreateServiceManagerConnector());
Sorin Jianua8ef73d2017-11-02 16:55:17225 component_unpacker->Unpack(base::BindOnce(
226 &ComponentInstallerTest::UnpackComplete, base::Unretained(this)));
Sorin Jianu316232a2017-05-26 20:22:30227 RunThreads();
228}
229
Sorin Jianu08f92b3c2017-09-25 16:17:12230void ComponentInstallerTest::UnpackComplete(
Sorin Jianu316232a2017-05-26 20:22:30231 const ComponentUnpacker::Result& result) {
232 result_ = result;
233
234 EXPECT_EQ(update_client::UnpackerError::kNone, result_.error);
235 EXPECT_EQ(0, result_.extended_error);
236
Sorin Jianua8ef73d2017-11-02 16:55:17237 main_thread_task_runner_->PostTask(FROM_HERE, quit_closure());
Sorin Jianu316232a2017-05-26 20:22:30238}
239
sorin6a57db92016-06-27 22:28:15240} // namespace
241
Sorin Jianu08f92b3c2017-09-25 16:17:12242// Tests that the component metadata is propagated from the component installer
243// and its component policy, through the instance of the CrxComponent, to the
244// component updater service.
245TEST_F(ComponentInstallerTest, RegisterComponent) {
sorin6a57db92016-06-27 22:28:15246 class LoopHandler {
247 public:
Sorin Jianua8ef73d2017-11-02 16:55:17248 LoopHandler(int max_cnt, base::OnceClosure quit_closure)
249 : max_cnt_(max_cnt), quit_closure_(std::move(quit_closure)) {}
sorin6a57db92016-06-27 22:28:15250
251 void OnUpdate(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38252 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin6a57db92016-06-27 22:28:15253 static int cnt = 0;
254 ++cnt;
255 if (cnt >= max_cnt_)
Sorin Jianua8ef73d2017-11-02 16:55:17256 std::move(quit_closure_).Run();
sorin6a57db92016-06-27 22:28:15257 }
258
259 private:
260 const int max_cnt_;
Sorin Jianua8ef73d2017-11-02 16:55:17261 base::OnceClosure quit_closure_;
sorin6a57db92016-06-27 22:28:15262 };
263
Sorin Jianu0bf4bd3f2017-06-01 23:42:32264 base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
265
sorin6a57db92016-06-27 22:28:15266 const std::string id("jebgalgnebhfojomionfpkfelancnnkf");
267
268 // Quit after one update check has been fired.
269 LoopHandler loop_handler(1, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38270 EXPECT_CALL(update_client(), DoUpdate(_, _))
sorin6a57db92016-06-27 22:28:15271 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
272
273 EXPECT_CALL(update_client(), GetCrxUpdateState(id, _)).Times(1);
274 EXPECT_CALL(update_client(), Stop()).Times(1);
275
Sorin Jianu08f92b3c2017-09-25 16:17:12276 auto installer = base::MakeRefCounted<ComponentInstaller>(
Sorin Jianua8926bf2018-03-09 21:02:53277 std::make_unique<MockInstallerPolicy>());
Sorin Jianua8ef73d2017-11-02 16:55:17278 installer->Register(component_updater(), base::OnceClosure());
sorin6a57db92016-06-27 22:28:15279
280 RunThreads();
281
282 CrxUpdateItem item;
283 EXPECT_TRUE(component_updater()->GetComponentDetails(id, &item));
284 const CrxComponent& component(item.component);
sorin2adb2ca2016-06-29 01:44:35285
286 update_client::InstallerAttributes expected_attrs;
287 expected_attrs["ap"] = "fake-ap";
288 expected_attrs["is-enterprise"] = "1";
289
sorin6a57db92016-06-27 22:28:15290 EXPECT_EQ(
291 std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
292 component.pk_hash);
293 EXPECT_EQ(base::Version("0.0.0.0"), component.version);
294 EXPECT_TRUE(component.fingerprint.empty());
295 EXPECT_STREQ("fake name", component.name.c_str());
sorin2adb2ca2016-06-29 01:44:35296 EXPECT_EQ(expected_attrs, component.installer_attributes);
sorin6a57db92016-06-27 22:28:15297 EXPECT_TRUE(component.requires_network_encryption);
sorin098a4a72016-08-30 04:43:24298 EXPECT_TRUE(component.supports_group_policy_enable_component_updates);
sorin6a57db92016-06-27 22:28:15299}
300
Sorin Jianu316232a2017-05-26 20:22:30301// Tests that the unpack path is removed when the install succeeded.
Sorin Jianu08f92b3c2017-09-25 16:17:12302TEST_F(ComponentInstallerTest, UnpackPathInstallSuccess) {
303 auto installer = base::MakeRefCounted<ComponentInstaller>(
Sorin Jianua8926bf2018-03-09 21:02:53304 std::make_unique<MockInstallerPolicy>());
Sorin Jianu316232a2017-05-26 20:22:30305
306 Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
307
308 const auto unpack_path = result().unpack_path;
309 EXPECT_TRUE(base::DirectoryExists(unpack_path));
Minh X. Nguyenaafd7632017-10-19 21:12:35310 EXPECT_EQ(update_client::jebg_public_key, result().public_key);
Sorin Jianu316232a2017-05-26 20:22:30311
Sorin Jianu316232a2017-05-26 20:22:30312 base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
313 base::FilePath base_dir;
314 EXPECT_TRUE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
315 base_dir = base_dir.Append(relative_install_dir);
316 EXPECT_TRUE(base::CreateDirectory(base_dir));
Sorin Jianuf40ab4b32017-10-06 22:53:41317 installer->Install(
Sorin Jianuea5534e92017-10-27 01:40:28318 unpack_path, update_client::jebg_public_key,
Sorin Jianua8ef73d2017-11-02 16:55:17319 base::BindOnce([](const update_client::CrxInstaller::Result& result) {
Sorin Jianuf40ab4b32017-10-06 22:53:41320 EXPECT_EQ(0, result.error);
321 }));
Sorin Jianu316232a2017-05-26 20:22:30322
Sorin Jianuf40ab4b32017-10-06 22:53:41323 scoped_task_environment_.RunUntilIdle();
324
325 EXPECT_FALSE(base::PathExists(unpack_path));
Sorin Jianu316232a2017-05-26 20:22:30326 EXPECT_CALL(update_client(), Stop()).Times(1);
327}
328
329// Tests that the unpack path is removed when the install failed.
Sorin Jianu08f92b3c2017-09-25 16:17:12330TEST_F(ComponentInstallerTest, UnpackPathInstallError) {
331 auto installer = base::MakeRefCounted<ComponentInstaller>(
Sorin Jianua8926bf2018-03-09 21:02:53332 std::make_unique<MockInstallerPolicy>());
Sorin Jianu316232a2017-05-26 20:22:30333
334 Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
335
336 const auto unpack_path = result().unpack_path;
337 EXPECT_TRUE(base::DirectoryExists(unpack_path));
338
Sorin Jianu316232a2017-05-26 20:22:30339 // Test the precondition that DIR_COMPONENT_USER is not registered with
340 // the path service.
341 base::FilePath base_dir;
342 EXPECT_FALSE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
343
344 // Calling |Install| fails since DIR_COMPONENT_USER does not exist.
Sorin Jianuf40ab4b32017-10-06 22:53:41345 installer->Install(
Sorin Jianuea5534e92017-10-27 01:40:28346 unpack_path, update_client::jebg_public_key,
Sorin Jianua8ef73d2017-11-02 16:55:17347 base::BindOnce([](const update_client::CrxInstaller::Result& result) {
Sorin Jianuf40ab4b32017-10-06 22:53:41348 EXPECT_EQ(static_cast<int>(
349 update_client::InstallError::NO_DIR_COMPONENT_USER),
350 result.error);
351 }));
Sorin Jianu316232a2017-05-26 20:22:30352
Sorin Jianuf40ab4b32017-10-06 22:53:41353 scoped_task_environment_.RunUntilIdle();
354
355 EXPECT_FALSE(base::PathExists(unpack_path));
Sorin Jianu316232a2017-05-26 20:22:30356 EXPECT_CALL(update_client(), Stop()).Times(1);
357}
358
sorin6a57db92016-06-27 22:28:15359} // namespace component_updater