blob: 6e3d9bb165292a1d9a86e92af3661f9cfbaa669d [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>
6#include <string>
waffles77255cc2016-08-02 17:25:127#include <utility>
sorin6a57db92016-06-27 22:28:158#include <vector>
9
Sorin Jianuf40ab4b32017-10-06 22:53:4110#include "base/bind.h"
sorin6a57db92016-06-27 22:28:1511#include "base/callback.h"
Sorin Jianu316232a2017-05-26 20:22:3012#include "base/files/file_path.h"
13#include "base/files/file_util.h"
sorin6a57db92016-06-27 22:28:1514#include "base/macros.h"
Sorin Jianu316232a2017-05-26 20:22:3015#include "base/memory/ptr_util.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"
sorin6a57db92016-06-27 22:28:1533#include "testing/gmock/include/gmock/gmock.h"
34#include "testing/gtest/include/gtest/gtest.h"
35
Sorin Jianu316232a2017-05-26 20:22:3036using ComponentUnpacker = update_client::ComponentUnpacker;
sorin6a57db92016-06-27 22:28:1537using Configurator = update_client::Configurator;
38using CrxUpdateItem = update_client::CrxUpdateItem;
39using TestConfigurator = update_client::TestConfigurator;
40using UpdateClient = update_client::UpdateClient;
41
42using ::testing::_;
43using ::testing::Invoke;
44
45namespace component_updater {
46
47namespace {
48
49// This hash corresponds to jebgalgnebhfojomionfpkfelancnnkf.crx.
50const uint8_t kSha256Hash[] = {0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec,
51 0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5,
52 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4,
53 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40};
54
Sorin Jianu316232a2017-05-26 20:22:3055constexpr base::FilePath::CharType relative_install_dir[] =
56 FILE_PATH_LITERAL("fake");
57
58base::FilePath test_file(const char* file) {
59 base::FilePath path;
60 PathService::Get(base::DIR_SOURCE_ROOT, &path);
61 return path.AppendASCII("components")
62 .AppendASCII("test")
63 .AppendASCII("data")
64 .AppendASCII("update_client")
65 .AppendASCII(file);
66}
67
sorin6a57db92016-06-27 22:28:1568class MockUpdateClient : public UpdateClient {
69 public:
sorin2adb2ca2016-06-29 01:44:3570 MockUpdateClient() {}
Vladislav Kuzkokov12eca792017-10-20 12:45:3871
72 void Install(const std::string& id,
73 const CrxDataCallback& crx_data_callback,
74 Callback callback) {
75 DoInstall(id, crx_data_callback);
76 std::move(callback).Run(update_client::Error::NONE);
77 }
78
79 void Update(const std::vector<std::string>& ids,
80 const CrxDataCallback& crx_data_callback,
81 Callback callback) {
82 DoUpdate(ids, crx_data_callback);
83 std::move(callback).Run(update_client::Error::NONE);
84 }
85
86 void SendUninstallPing(const std::string& id,
87 const base::Version& version,
88 int reason,
89 Callback callback) {
90 DoSendUninstallPing(id, version, reason);
91 std::move(callback).Run(update_client::Error::NONE);
92 }
93
sorin6a57db92016-06-27 22:28:1594 MOCK_METHOD1(AddObserver, void(Observer* observer));
95 MOCK_METHOD1(RemoveObserver, void(Observer* observer));
Vladislav Kuzkokov12eca792017-10-20 12:45:3896 MOCK_METHOD2(DoInstall,
sorin6a57db92016-06-27 22:28:1597 void(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:3898 const CrxDataCallback& crx_data_callback));
99 MOCK_METHOD2(DoUpdate,
sorin6a57db92016-06-27 22:28:15100 void(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38101 const CrxDataCallback& crx_data_callback));
sorin6a57db92016-06-27 22:28:15102 MOCK_CONST_METHOD2(GetCrxUpdateState,
103 bool(const std::string& id, CrxUpdateItem* update_item));
104 MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
105 MOCK_METHOD0(Stop, void());
Vladislav Kuzkokov12eca792017-10-20 12:45:38106 MOCK_METHOD3(DoSendUninstallPing,
sorin8037ac8c2017-04-19 16:28:00107 void(const std::string& id,
108 const base::Version& version,
Vladislav Kuzkokov12eca792017-10-20 12:45:38109 int reason));
sorin6a57db92016-06-27 22:28:15110
111 private:
sorin2adb2ca2016-06-29 01:44:35112 ~MockUpdateClient() override {}
sorin6a57db92016-06-27 22:28:15113};
114
Sorin Jianu08f92b3c2017-09-25 16:17:12115class FakeInstallerPolicy : public ComponentInstallerPolicy {
sorin6a57db92016-06-27 22:28:15116 public:
Sorin Jianu08f92b3c2017-09-25 16:17:12117 FakeInstallerPolicy() {}
118 ~FakeInstallerPolicy() override {}
sorin6a57db92016-06-27 22:28:15119
120 bool VerifyInstallation(const base::DictionaryValue& manifest,
121 const base::FilePath& dir) const override {
122 return true;
123 }
124
sorin3574ef92016-08-03 16:46:01125 bool SupportsGroupPolicyEnabledComponentUpdates() const override {
sorin098a4a72016-08-30 04:43:24126 return true;
sorin3574ef92016-08-03 16:46:01127 }
sorin6a57db92016-06-27 22:28:15128
129 bool RequiresNetworkEncryption() const override { return true; }
130
sorin2892f7212016-11-07 18:59:43131 update_client::CrxInstaller::Result OnCustomInstall(
132 const base::DictionaryValue& manifest,
133 const base::FilePath& install_dir) override {
134 return update_client::CrxInstaller::Result(0);
sorin6a57db92016-06-27 22:28:15135 }
136
137 void ComponentReady(
138 const base::Version& version,
139 const base::FilePath& install_dir,
140 std::unique_ptr<base::DictionaryValue> manifest) override {}
141
142 base::FilePath GetRelativeInstallDir() const override {
Sorin Jianu316232a2017-05-26 20:22:30143 return base::FilePath(relative_install_dir);
sorin6a57db92016-06-27 22:28:15144 }
145
146 void GetHash(std::vector<uint8_t>* hash) const override { GetPkHash(hash); }
147
148 std::string GetName() const override { return "fake name"; }
149
sorin2adb2ca2016-06-29 01:44:35150 update_client::InstallerAttributes GetInstallerAttributes() const override {
151 update_client::InstallerAttributes installer_attributes;
152 installer_attributes["ap"] = "fake-ap";
153 installer_attributes["is-enterprise"] = "1";
154 return installer_attributes;
155 }
sorin6a57db92016-06-27 22:28:15156
waffles77255cc2016-08-02 17:25:12157 std::vector<std::string> GetMimeTypes() const override {
158 return std::vector<std::string>();
159 }
160
sorin6a57db92016-06-27 22:28:15161 private:
162 static void GetPkHash(std::vector<uint8_t>* hash) {
163 hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
164 }
165};
166
Sorin Jianu08f92b3c2017-09-25 16:17:12167class ComponentInstallerTest : public testing::Test {
sorin6a57db92016-06-27 22:28:15168 public:
Sorin Jianu08f92b3c2017-09-25 16:17:12169 ComponentInstallerTest();
170 ~ComponentInstallerTest() override;
sorin6a57db92016-06-27 22:28:15171
172 MockUpdateClient& update_client() { return *update_client_; }
173 ComponentUpdateService* component_updater() {
174 return component_updater_.get();
175 }
176 scoped_refptr<TestConfigurator> configurator() const { return config_; }
177 base::Closure quit_closure() const { return quit_closure_; }
178
179 protected:
180 void RunThreads();
Sorin Jianu316232a2017-05-26 20:22:30181 void Unpack(const base::FilePath& crx_path);
182 ComponentUnpacker::Result result() const { return result_; }
sorin6a57db92016-06-27 22:28:15183
Sorin Jianuf40ab4b32017-10-06 22:53:41184 base::test::ScopedTaskEnvironment scoped_task_environment_;
185
sorin6a57db92016-06-27 22:28:15186 private:
Sorin Jianu316232a2017-05-26 20:22:30187 void UnpackComplete(const ComponentUnpacker::Result& result);
188
Sorin Jianu316232a2017-05-26 20:22:30189 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_ =
190 base::ThreadTaskRunnerHandle::Get();
sorin6a57db92016-06-27 22:28:15191 base::RunLoop runloop_;
Sorin Jianucc048f892017-07-26 02:05:54192 base::Closure quit_closure_ = runloop_.QuitClosure();
sorin6a57db92016-06-27 22:28:15193
Sorin Jianucc048f892017-07-26 02:05:54194 scoped_refptr<TestConfigurator> config_ =
195 base::MakeRefCounted<TestConfigurator>();
196 scoped_refptr<MockUpdateClient> update_client_ =
197 base::MakeRefCounted<MockUpdateClient>();
sorin6a57db92016-06-27 22:28:15198 std::unique_ptr<ComponentUpdateService> component_updater_;
Sorin Jianu316232a2017-05-26 20:22:30199 ComponentUnpacker::Result result_;
sorin6a57db92016-06-27 22:28:15200};
201
Sorin Jianu08f92b3c2017-09-25 16:17:12202ComponentInstallerTest::ComponentInstallerTest() {
sorin6a57db92016-06-27 22:28:15203 EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
Sorin Jianu316232a2017-05-26 20:22:30204 component_updater_ =
205 base::MakeUnique<CrxUpdateService>(config_, update_client_);
sorin6a57db92016-06-27 22:28:15206}
207
Sorin Jianu08f92b3c2017-09-25 16:17:12208ComponentInstallerTest::~ComponentInstallerTest() {
sorin6a57db92016-06-27 22:28:15209 EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
210 component_updater_.reset();
211}
212
Sorin Jianu08f92b3c2017-09-25 16:17:12213void ComponentInstallerTest::RunThreads() {
sorin6a57db92016-06-27 22:28:15214 runloop_.Run();
215}
216
Sorin Jianu08f92b3c2017-09-25 16:17:12217void ComponentInstallerTest::Unpack(const base::FilePath& crx_path) {
Sorin Jianu316232a2017-05-26 20:22:30218 auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
219 std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
Sorin Jianuebd652462017-07-23 02:00:58220 crx_path, nullptr, nullptr);
Sorin Jianu08f92b3c2017-09-25 16:17:12221 component_unpacker->Unpack(base::Bind(&ComponentInstallerTest::UnpackComplete,
222 base::Unretained(this)));
Sorin Jianu316232a2017-05-26 20:22:30223 RunThreads();
224}
225
Sorin Jianu08f92b3c2017-09-25 16:17:12226void ComponentInstallerTest::UnpackComplete(
Sorin Jianu316232a2017-05-26 20:22:30227 const ComponentUnpacker::Result& result) {
228 result_ = result;
229
230 EXPECT_EQ(update_client::UnpackerError::kNone, result_.error);
231 EXPECT_EQ(0, result_.extended_error);
232
233 main_thread_task_runner_->PostTask(FROM_HERE, quit_closure_);
234}
235
sorin6a57db92016-06-27 22:28:15236} // namespace
237
Sorin Jianu08f92b3c2017-09-25 16:17:12238// Tests that the component metadata is propagated from the component installer
239// and its component policy, through the instance of the CrxComponent, to the
240// component updater service.
241TEST_F(ComponentInstallerTest, RegisterComponent) {
sorin6a57db92016-06-27 22:28:15242 class LoopHandler {
243 public:
244 LoopHandler(int max_cnt, const base::Closure& quit_closure)
245 : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
246
247 void OnUpdate(const std::vector<std::string>& ids,
Vladislav Kuzkokov12eca792017-10-20 12:45:38248 const UpdateClient::CrxDataCallback& crx_data_callback) {
sorin6a57db92016-06-27 22:28:15249 static int cnt = 0;
250 ++cnt;
251 if (cnt >= max_cnt_)
252 quit_closure_.Run();
253 }
254
255 private:
256 const int max_cnt_;
257 base::Closure quit_closure_;
258 };
259
Sorin Jianu0bf4bd3f2017-06-01 23:42:32260 base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
261
sorin6a57db92016-06-27 22:28:15262 const std::string id("jebgalgnebhfojomionfpkfelancnnkf");
263
264 // Quit after one update check has been fired.
265 LoopHandler loop_handler(1, quit_closure());
Vladislav Kuzkokov12eca792017-10-20 12:45:38266 EXPECT_CALL(update_client(), DoUpdate(_, _))
sorin6a57db92016-06-27 22:28:15267 .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
268
269 EXPECT_CALL(update_client(), GetCrxUpdateState(id, _)).Times(1);
270 EXPECT_CALL(update_client(), Stop()).Times(1);
271
Sorin Jianu08f92b3c2017-09-25 16:17:12272 auto installer = base::MakeRefCounted<ComponentInstaller>(
273 base::MakeUnique<FakeInstallerPolicy>());
sorin6a57db92016-06-27 22:28:15274 installer->Register(component_updater(), base::Closure());
275
276 RunThreads();
277
278 CrxUpdateItem item;
279 EXPECT_TRUE(component_updater()->GetComponentDetails(id, &item));
280 const CrxComponent& component(item.component);
sorin2adb2ca2016-06-29 01:44:35281
282 update_client::InstallerAttributes expected_attrs;
283 expected_attrs["ap"] = "fake-ap";
284 expected_attrs["is-enterprise"] = "1";
285
sorin6a57db92016-06-27 22:28:15286 EXPECT_EQ(
287 std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
288 component.pk_hash);
289 EXPECT_EQ(base::Version("0.0.0.0"), component.version);
290 EXPECT_TRUE(component.fingerprint.empty());
291 EXPECT_STREQ("fake name", component.name.c_str());
sorin2adb2ca2016-06-29 01:44:35292 EXPECT_EQ(expected_attrs, component.installer_attributes);
sorin6a57db92016-06-27 22:28:15293 EXPECT_TRUE(component.requires_network_encryption);
sorin098a4a72016-08-30 04:43:24294 EXPECT_TRUE(component.supports_group_policy_enable_component_updates);
sorin6a57db92016-06-27 22:28:15295}
296
Sorin Jianu316232a2017-05-26 20:22:30297// Tests that the unpack path is removed when the install succeeded.
Sorin Jianu08f92b3c2017-09-25 16:17:12298TEST_F(ComponentInstallerTest, UnpackPathInstallSuccess) {
299 auto installer = base::MakeRefCounted<ComponentInstaller>(
300 base::MakeUnique<FakeInstallerPolicy>());
Sorin Jianu316232a2017-05-26 20:22:30301
302 Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
303
304 const auto unpack_path = result().unpack_path;
305 EXPECT_TRUE(base::DirectoryExists(unpack_path));
Minh X. Nguyenaafd7632017-10-19 21:12:35306 EXPECT_EQ(update_client::jebg_public_key, result().public_key);
Sorin Jianu316232a2017-05-26 20:22:30307
Sorin Jianu316232a2017-05-26 20:22:30308 base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
309 base::FilePath base_dir;
310 EXPECT_TRUE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
311 base_dir = base_dir.Append(relative_install_dir);
312 EXPECT_TRUE(base::CreateDirectory(base_dir));
Sorin Jianuf40ab4b32017-10-06 22:53:41313 installer->Install(
Sorin Jianu7aa6d1f2017-10-13 20:29:29314 unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:41315 base::Bind([](const update_client::CrxInstaller::Result& result) {
316 EXPECT_EQ(0, result.error);
317 }));
Sorin Jianu316232a2017-05-26 20:22:30318
Sorin Jianuf40ab4b32017-10-06 22:53:41319 scoped_task_environment_.RunUntilIdle();
320
321 EXPECT_FALSE(base::PathExists(unpack_path));
Sorin Jianu316232a2017-05-26 20:22:30322 EXPECT_CALL(update_client(), Stop()).Times(1);
323}
324
325// Tests that the unpack path is removed when the install failed.
Sorin Jianu08f92b3c2017-09-25 16:17:12326TEST_F(ComponentInstallerTest, UnpackPathInstallError) {
327 auto installer = base::MakeRefCounted<ComponentInstaller>(
328 base::MakeUnique<FakeInstallerPolicy>());
Sorin Jianu316232a2017-05-26 20:22:30329
330 Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
331
332 const auto unpack_path = result().unpack_path;
333 EXPECT_TRUE(base::DirectoryExists(unpack_path));
334
Sorin Jianu316232a2017-05-26 20:22:30335 // Test the precondition that DIR_COMPONENT_USER is not registered with
336 // the path service.
337 base::FilePath base_dir;
338 EXPECT_FALSE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
339
340 // Calling |Install| fails since DIR_COMPONENT_USER does not exist.
Sorin Jianuf40ab4b32017-10-06 22:53:41341 installer->Install(
Sorin Jianu7aa6d1f2017-10-13 20:29:29342 unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:41343 base::Bind([](const update_client::CrxInstaller::Result& result) {
344 EXPECT_EQ(static_cast<int>(
345 update_client::InstallError::NO_DIR_COMPONENT_USER),
346 result.error);
347 }));
Sorin Jianu316232a2017-05-26 20:22:30348
Sorin Jianuf40ab4b32017-10-06 22:53:41349 scoped_task_environment_.RunUntilIdle();
350
351 EXPECT_FALSE(base::PathExists(unpack_path));
Sorin Jianu316232a2017-05-26 20:22:30352 EXPECT_CALL(update_client(), Stop()).Times(1);
353}
354
sorin6a57db92016-06-27 22:28:15355} // namespace component_updater