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