|  | // Copyright 2017 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/functional/bind.h" | 
|  | #include "base/functional/callback_helpers.h" | 
|  | #include "base/memory/scoped_refptr.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "components/update_client/update_client.h" | 
|  | #include "components/update_client/update_client_errors.h" | 
|  | #include "content/public/test/test_utils.h" | 
|  | #include "extensions/browser/extensions_test.h" | 
|  | #include "extensions/browser/updater/extension_installer.h" | 
|  | #include "extensions/common/extension_id.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class ExtensionInstallerTest : public ExtensionsTest { | 
|  | public: | 
|  | using UpdateClientCallback = | 
|  | extensions::ExtensionInstaller::UpdateClientCallback; | 
|  | using ExtensionInstallerCallback = | 
|  | ExtensionInstaller::ExtensionInstallerCallback; | 
|  | using Result = update_client::CrxInstaller::Result; | 
|  | using InstallError = update_client::InstallError; | 
|  |  | 
|  | ExtensionInstallerTest(); | 
|  |  | 
|  | ExtensionInstallerTest(const ExtensionInstallerTest&) = delete; | 
|  | ExtensionInstallerTest& operator=(const ExtensionInstallerTest&) = delete; | 
|  |  | 
|  | ~ExtensionInstallerTest() override; | 
|  |  | 
|  | void InstallCompleteCallback(const Result& result); | 
|  |  | 
|  | protected: | 
|  | void RunThreads(); | 
|  |  | 
|  | protected: | 
|  | const std::string kExtensionId = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; | 
|  | const std::string kPublicKey = | 
|  | "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/" | 
|  | "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j" | 
|  | "kDuI7caxEGUucpP7GJRRHnm8Sx+" | 
|  | "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB"; | 
|  |  | 
|  | base::RunLoop run_loop_; | 
|  | Result result_; | 
|  | bool executed_; | 
|  | }; | 
|  |  | 
|  | ExtensionInstallerTest::ExtensionInstallerTest() | 
|  | : result_(-1), executed_(false) {} | 
|  |  | 
|  | ExtensionInstallerTest::~ExtensionInstallerTest() = default; | 
|  |  | 
|  | void ExtensionInstallerTest::InstallCompleteCallback(const Result& result) { | 
|  | result_ = result; | 
|  | executed_ = true; | 
|  | run_loop_.Quit(); | 
|  | } | 
|  |  | 
|  | void ExtensionInstallerTest::RunThreads() { | 
|  | run_loop_.Run(); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionInstallerTest, GetInstalledFile) { | 
|  | base::ScopedTempDir root_dir; | 
|  | ASSERT_TRUE(root_dir.CreateUniqueTempDir()); | 
|  | ASSERT_FALSE(base::MakeRefCounted<ExtensionInstaller>( | 
|  | kExtensionId, root_dir.GetPath(), | 
|  | false /*install_immediately*/, ExtensionInstallerCallback()) | 
|  | ->GetInstalledFile("f")); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionInstallerTest, Install_InvalidUnpackedDir) { | 
|  | // The unpacked folder is not valid, the installer will return an error. | 
|  | base::ScopedTempDir root_dir; | 
|  | ASSERT_TRUE(root_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(root_dir.GetPath())); | 
|  | scoped_refptr<ExtensionInstaller> installer = | 
|  | base::MakeRefCounted<ExtensionInstaller>( | 
|  | kExtensionId, root_dir.GetPath(), true /*install_immediately*/, | 
|  | base::BindRepeating( | 
|  | [](const ExtensionId& extension_id, const std::string& public_key, | 
|  | const base::FilePath& unpacked_dir, bool install_immediately, | 
|  | UpdateClientCallback update_client_callback) { | 
|  | // This function should never be executed. | 
|  | EXPECT_TRUE(false); | 
|  | })); | 
|  |  | 
|  | // Non-existing unpacked dir | 
|  | base::ScopedTempDir unpacked_dir; | 
|  | ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath())); | 
|  | ASSERT_TRUE(base::DeletePathRecursively(unpacked_dir.GetPath())); | 
|  | ASSERT_FALSE(base::PathExists(unpacked_dir.GetPath())); | 
|  | installer->Install( | 
|  | unpacked_dir.GetPath(), kPublicKey, nullptr, base::DoNothing(), | 
|  | base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | RunThreads(); | 
|  |  | 
|  | EXPECT_TRUE(executed_); | 
|  | EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.result.code); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Error) { | 
|  | base::ScopedTempDir root_dir; | 
|  | ASSERT_TRUE(root_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(root_dir.GetPath())); | 
|  | scoped_refptr<ExtensionInstaller> installer = | 
|  | base::MakeRefCounted<ExtensionInstaller>( | 
|  | kExtensionId, root_dir.GetPath(), false /*install_immediately*/, | 
|  | base::BindRepeating([](const ExtensionId& extension_id, | 
|  | const std::string& public_key, | 
|  | const base::FilePath& unpacked_dir, | 
|  | bool install_immediately, | 
|  | UpdateClientCallback update_client_callback) { | 
|  | EXPECT_FALSE(install_immediately); | 
|  | std::move(update_client_callback) | 
|  | .Run(Result(InstallError::GENERIC_ERROR)); | 
|  | })); | 
|  |  | 
|  | base::ScopedTempDir unpacked_dir; | 
|  | ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath())); | 
|  |  | 
|  | installer->Install( | 
|  | unpacked_dir.GetPath(), kPublicKey, nullptr, base::DoNothing(), | 
|  | base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | RunThreads(); | 
|  |  | 
|  | EXPECT_TRUE(executed_); | 
|  | EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.result.code); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Success) { | 
|  | base::ScopedTempDir root_dir; | 
|  | ASSERT_TRUE(root_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(root_dir.GetPath())); | 
|  | scoped_refptr<ExtensionInstaller> installer = | 
|  | base::MakeRefCounted<ExtensionInstaller>( | 
|  | kExtensionId, root_dir.GetPath(), true /*install_immediately*/, | 
|  | base::BindRepeating([](const ExtensionId& extension_id, | 
|  | const std::string& public_key, | 
|  | const base::FilePath& unpacked_dir, | 
|  | bool install_immediately, | 
|  | UpdateClientCallback update_client_callback) { | 
|  | EXPECT_TRUE(install_immediately); | 
|  | std::move(update_client_callback).Run(Result(InstallError::NONE)); | 
|  | })); | 
|  |  | 
|  | base::ScopedTempDir unpacked_dir; | 
|  | ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath())); | 
|  |  | 
|  | installer->Install( | 
|  | unpacked_dir.GetPath(), kPublicKey, nullptr, base::DoNothing(), | 
|  | base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback, | 
|  | base::Unretained(this))); | 
|  |  | 
|  | RunThreads(); | 
|  |  | 
|  | EXPECT_TRUE(executed_); | 
|  | EXPECT_EQ(static_cast<int>(InstallError::NONE), result_.result.code); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | }  // namespace extensions |