blob: f1f503cbc9e75d4befbc51eff8e5216c956edb6d [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/updater/extension_installer.h"
#include <memory>
#include <string>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.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 "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() 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_;
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallerTest);
};
ExtensionInstallerTest::ExtensionInstallerTest()
: result_(-1), executed_(false) {}
ExtensionInstallerTest::~ExtensionInstallerTest() {}
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_TRUE(base::PathExists(root_dir.GetPath()));
scoped_refptr<ExtensionInstaller> installer =
base::MakeRefCounted<ExtensionInstaller>(kExtensionId, root_dir.GetPath(),
false /*install_immediately*/,
ExtensionInstallerCallback());
base::FilePath installed_file;
#ifdef FILE_PATH_USES_DRIVE_LETTERS
const std::string absolute_path = "C:\\abc\\def";
const std::string relative_path = "abc\\..\\def\\ghi";
#else
const std::string absolute_path = "/abc/def";
const std::string relative_path = "/abc/../def/ghi";
#endif
installed_file.clear();
EXPECT_FALSE(installer->GetInstalledFile(absolute_path, &installed_file));
installed_file.clear();
EXPECT_FALSE(installer->GetInstalledFile(relative_path, &installed_file));
installed_file.clear();
EXPECT_FALSE(installer->GetInstalledFile("extension", &installed_file));
installed_file.clear();
base::FilePath temp_file;
ASSERT_TRUE(base::CreateTemporaryFileInDir(root_dir.GetPath(), &temp_file));
base::FilePath base_temp_file = temp_file.BaseName();
EXPECT_TRUE(installer->GetInstalledFile(
std::string(base_temp_file.value().begin(), base_temp_file.value().end()),
&installed_file));
#ifndef FILE_PATH_USES_DRIVE_LETTERS
// On some Win*, this test is flaky because of the way Win* constructs path.
// For example,
// "C:\Users\chrome-bot\AppData" is the same as "C:\Users\CHROME~1\AppData"
EXPECT_EQ(temp_file, installed_file);
#endif
}
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::BindOnce(
[](const std::string& 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::DeleteFile(unpacked_dir.GetPath(), true));
ASSERT_FALSE(base::PathExists(unpacked_dir.GetPath()));
installer->Install(
unpacked_dir.GetPath(), kPublicKey,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
RunThreads();
EXPECT_TRUE(executed_);
EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
}
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::BindOnce([](const std::string& 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,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
RunThreads();
EXPECT_TRUE(executed_);
EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
}
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::BindOnce([](const std::string& 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,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
RunThreads();
EXPECT_TRUE(executed_);
EXPECT_EQ(static_cast<int>(InstallError::NONE), result_.error);
}
} // namespace
} // namespace extensions