1 // Copyright 2017 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 <memory>
6 #include <string>
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/scoped_refptr.h"
14 #include "base/run_loop.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "components/update_client/update_client.h"
17 #include "components/update_client/update_client_errors.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/extensions_test.h"
20 #include "extensions/browser/updater/extension_installer.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace extensions {
24
25 namespace {
26
27 class ExtensionInstallerTest : public ExtensionsTest {
28 public:
29 using UpdateClientCallback =
30 extensions::ExtensionInstaller::UpdateClientCallback;
31 using ExtensionInstallerCallback =
32 ExtensionInstaller::ExtensionInstallerCallback;
33 using Result = update_client::CrxInstaller::Result;
34 using InstallError = update_client::InstallError;
35
36 ExtensionInstallerTest();
37 ~ExtensionInstallerTest() override;
38
39 void InstallCompleteCallback(const Result& result);
40
41 protected:
42 void RunThreads();
43
44 protected:
45 const std::string kExtensionId = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
46 const std::string kPublicKey =
47 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
48 "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
49 "kDuI7caxEGUucpP7GJRRHnm8Sx+"
50 "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
51
52 base::RunLoop run_loop_;
53 Result result_;
54 bool executed_;
55
56 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallerTest);
57 };
58
ExtensionInstallerTest()59 ExtensionInstallerTest::ExtensionInstallerTest()
60 : result_(-1), executed_(false) {}
61
62 ExtensionInstallerTest::~ExtensionInstallerTest() = default;
63
InstallCompleteCallback(const Result & result)64 void ExtensionInstallerTest::InstallCompleteCallback(const Result& result) {
65 result_ = result;
66 executed_ = true;
67 run_loop_.Quit();
68 }
69
RunThreads()70 void ExtensionInstallerTest::RunThreads() {
71 run_loop_.Run();
72 }
73
TEST_F(ExtensionInstallerTest,GetInstalledFile)74 TEST_F(ExtensionInstallerTest, GetInstalledFile) {
75 base::ScopedTempDir root_dir;
76 ASSERT_TRUE(root_dir.CreateUniqueTempDir());
77 ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
78 scoped_refptr<ExtensionInstaller> installer =
79 base::MakeRefCounted<ExtensionInstaller>(kExtensionId, root_dir.GetPath(),
80 false /*install_immediately*/,
81 ExtensionInstallerCallback());
82
83 base::FilePath installed_file;
84
85 #ifdef FILE_PATH_USES_DRIVE_LETTERS
86 const std::string absolute_path = "C:\\abc\\def";
87 const std::string relative_path = "abc\\..\\def\\ghi";
88 #else
89 const std::string absolute_path = "/abc/def";
90 const std::string relative_path = "/abc/../def/ghi";
91 #endif
92
93 installed_file.clear();
94 EXPECT_FALSE(installer->GetInstalledFile(absolute_path, &installed_file));
95 installed_file.clear();
96 EXPECT_FALSE(installer->GetInstalledFile(relative_path, &installed_file));
97 installed_file.clear();
98 EXPECT_FALSE(installer->GetInstalledFile("extension", &installed_file));
99
100 installed_file.clear();
101 base::FilePath temp_file;
102 ASSERT_TRUE(base::CreateTemporaryFileInDir(root_dir.GetPath(), &temp_file));
103 base::FilePath base_temp_file = temp_file.BaseName();
104 EXPECT_TRUE(installer->GetInstalledFile(
105 std::string(base_temp_file.value().begin(), base_temp_file.value().end()),
106 &installed_file));
107 #ifndef FILE_PATH_USES_DRIVE_LETTERS
108 // On some Win*, this test is flaky because of the way Win* constructs path.
109 // For example,
110 // "C:\Users\chrome-bot\AppData" is the same as "C:\Users\CHROME~1\AppData"
111 EXPECT_EQ(temp_file, installed_file);
112 #endif
113 }
114
TEST_F(ExtensionInstallerTest,Install_InvalidUnpackedDir)115 TEST_F(ExtensionInstallerTest, Install_InvalidUnpackedDir) {
116 // The unpacked folder is not valid, the installer will return an error.
117 base::ScopedTempDir root_dir;
118 ASSERT_TRUE(root_dir.CreateUniqueTempDir());
119 ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
120 scoped_refptr<ExtensionInstaller> installer =
121 base::MakeRefCounted<ExtensionInstaller>(
122 kExtensionId, root_dir.GetPath(), true /*install_immediately*/,
123 base::BindRepeating(
124 [](const std::string& extension_id, const std::string& public_key,
125 const base::FilePath& unpacked_dir, bool install_immediately,
126 UpdateClientCallback update_client_callback) {
127 // This function should never be executed.
128 EXPECT_TRUE(false);
129 }));
130
131 // Non-existing unpacked dir
132 base::ScopedTempDir unpacked_dir;
133 ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
134 ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
135 ASSERT_TRUE(base::DeleteFileRecursively(unpacked_dir.GetPath()));
136 ASSERT_FALSE(base::PathExists(unpacked_dir.GetPath()));
137 installer->Install(
138 unpacked_dir.GetPath(), kPublicKey, nullptr,
139 base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
140 base::Unretained(this)));
141
142 RunThreads();
143
144 EXPECT_TRUE(executed_);
145 EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
146 }
147
TEST_F(ExtensionInstallerTest,Install_BasicInstallOperation_Error)148 TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Error) {
149 base::ScopedTempDir root_dir;
150 ASSERT_TRUE(root_dir.CreateUniqueTempDir());
151 ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
152 scoped_refptr<ExtensionInstaller> installer =
153 base::MakeRefCounted<ExtensionInstaller>(
154 kExtensionId, root_dir.GetPath(), false /*install_immediately*/,
155 base::BindRepeating([](const std::string& extension_id,
156 const std::string& public_key,
157 const base::FilePath& unpacked_dir,
158 bool install_immediately,
159 UpdateClientCallback update_client_callback) {
160 EXPECT_FALSE(install_immediately);
161 std::move(update_client_callback)
162 .Run(Result(InstallError::GENERIC_ERROR));
163 }));
164
165 base::ScopedTempDir unpacked_dir;
166 ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
167 ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
168
169 installer->Install(
170 unpacked_dir.GetPath(), kPublicKey, nullptr,
171 base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
172 base::Unretained(this)));
173
174 RunThreads();
175
176 EXPECT_TRUE(executed_);
177 EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
178 }
179
TEST_F(ExtensionInstallerTest,Install_BasicInstallOperation_Success)180 TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Success) {
181 base::ScopedTempDir root_dir;
182 ASSERT_TRUE(root_dir.CreateUniqueTempDir());
183 ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
184 scoped_refptr<ExtensionInstaller> installer =
185 base::MakeRefCounted<ExtensionInstaller>(
186 kExtensionId, root_dir.GetPath(), true /*install_immediately*/,
187 base::BindRepeating([](const std::string& extension_id,
188 const std::string& public_key,
189 const base::FilePath& unpacked_dir,
190 bool install_immediately,
191 UpdateClientCallback update_client_callback) {
192 EXPECT_TRUE(install_immediately);
193 std::move(update_client_callback).Run(Result(InstallError::NONE));
194 }));
195
196 base::ScopedTempDir unpacked_dir;
197 ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
198 ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
199
200 installer->Install(
201 unpacked_dir.GetPath(), kPublicKey, nullptr,
202 base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
203 base::Unretained(this)));
204
205 RunThreads();
206
207 EXPECT_TRUE(executed_);
208 EXPECT_EQ(static_cast<int>(InstallError::NONE), result_.error);
209 }
210
211 } // namespace
212
213 } // namespace extensions
214