Commit fe9c3334 authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Adds some unittests for cros_component_installer_chromeos

The CL adds test coverage for CrOSComponentInstaller::Load method.
The tests set up fake components in a scoped test dir (containing
only manifest files) which is used to override component paths provided
by path service, and verify that Load requests load appropriate
component, issue on demand update requests as expected, and issue
requests to load the components to image loader service.

The focus in this cl is to add tests for behavior used for loading
demo-mode-resources component, but the set of tests can be expanded in
the future.

Change-Id: Ib4c2fab67492f1e62a3a1b3f1343139b9aa5baeb
Reviewed-on: https://chromium-review.googlesource.com/c/1278635Reviewed-by: default avatarJoshua Pawlicki <waffles@chromium.org>
Reviewed-by: default avatarDan Erat <derat@chromium.org>
Reviewed-by: default avatarXiaochu Liu <xiaochu@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601214}
parent 1a8346a5
......@@ -114,7 +114,8 @@ void BrowserProcessPlatformPart::InitializeCrosComponentManager() {
cros_component_manager_ =
std::make_unique<component_updater::CrOSComponentInstaller>(
component_updater::MetadataTable::Create(
g_browser_process->local_state()));
g_browser_process->local_state()),
g_browser_process->component_updater());
// Register all installed components for regular update.
cros_component_manager_->RegisterInstalled();
......
......@@ -37,6 +37,8 @@ std::string ErrorToString(
case component_updater::CrOSComponentManager::Error::
COMPATIBILITY_CHECK_FAILED:
return "COMPATIBILITY_CHECK_FAILED";
case component_updater::CrOSComponentManager::Error::NOT_FOUND:
return "NOT_FOUND";
case component_updater::CrOSComponentManager::Error::ERROR_MAX:
return "ERROR_MAX";
}
......
......@@ -203,8 +203,10 @@ bool CrOSComponentInstallerPolicy::IsCompatible(
}
CrOSComponentInstaller::CrOSComponentInstaller(
std::unique_ptr<MetadataTable> metadata_table)
: metadata_table_(std::move(metadata_table)) {}
std::unique_ptr<MetadataTable> metadata_table,
ComponentUpdateService* component_updater)
: metadata_table_(std::move(metadata_table)),
component_updater_(component_updater) {}
CrOSComponentInstaller::~CrOSComponentInstaller() {}
......@@ -219,8 +221,7 @@ void CrOSComponentInstaller::Load(const std::string& name,
if (!IsCompatible(name) || update_policy == UpdatePolicy::kForce) {
// A compatible component is not installed, or forced update is requested.
// Start registration and installation/update process.
auto* const cus = g_browser_process->component_updater();
Install(cus, name, update_policy, mount_policy, std::move(load_callback));
Install(name, update_policy, mount_policy, std::move(load_callback));
} else if (mount_policy == MountPolicy::kMount) {
// A compatible component is installed, load it.
LoadInternal(name, std::move(load_callback));
......@@ -238,11 +239,10 @@ bool CrOSComponentInstaller::Unload(const std::string& name) {
// Component |name| does not exist.
return false;
}
ComponentUpdateService* updater = g_browser_process->component_updater();
const std::string id = GenerateId(config->sha2hash);
metadata_table_->DeleteComponentForCurrentUser(name);
return metadata_table_->HasComponentForAnyUser(name) ||
updater->UnregisterComponent(id);
component_updater_->UnregisterComponent(id);
}
void CrOSComponentInstaller::RegisterInstalled() {
......@@ -281,16 +281,14 @@ bool CrOSComponentInstaller::IsRegistered(const std::string& name) const {
return base::PathExists(root.Append(kComponentsRootPath).Append(name));
}
void CrOSComponentInstaller::Register(ComponentUpdateService* cus,
const ComponentConfig& config,
void CrOSComponentInstaller::Register(const ComponentConfig& config,
base::OnceClosure register_callback) {
auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<CrOSComponentInstallerPolicy>(config, this));
installer->Register(cus, std::move(register_callback));
installer->Register(component_updater_, std::move(register_callback));
}
void CrOSComponentInstaller::Install(ComponentUpdateService* cus,
const std::string& name,
void CrOSComponentInstaller::Install(const std::string& name,
UpdatePolicy update_policy,
MountPolicy mount_policy,
LoadCallback load_callback) {
......@@ -303,17 +301,16 @@ void CrOSComponentInstaller::Install(ComponentUpdateService* cus,
return;
}
Register(cus, *config,
Register(*config,
base::BindOnce(
&CrOSComponentInstaller::StartInstall, base::Unretained(this),
cus, name, GenerateId(config->sha2hash), update_policy,
name, GenerateId(config->sha2hash), update_policy,
base::BindOnce(&CrOSComponentInstaller::FinishInstall,
base::Unretained(this), name, mount_policy,
std::move(load_callback))));
update_policy, std::move(load_callback))));
}
void CrOSComponentInstaller::StartInstall(
ComponentUpdateService* cus,
const std::string& name,
const std::string& id,
UpdatePolicy update_policy,
......@@ -332,12 +329,13 @@ void CrOSComponentInstaller::StartInstall(
const component_updater::OnDemandUpdater::Priority priority =
is_compatible ? component_updater::OnDemandUpdater::Priority::BACKGROUND
: component_updater::OnDemandUpdater::Priority::FOREGROUND;
cus->GetOnDemandUpdater().OnDemandUpdate(id, priority,
std::move(install_callback));
component_updater_->GetOnDemandUpdater().OnDemandUpdate(
id, priority, std::move(install_callback));
}
void CrOSComponentInstaller::FinishInstall(const std::string& name,
MountPolicy mount_policy,
UpdatePolicy update_policy,
LoadCallback load_callback,
update_client::Error error) {
if (error != update_client::Error::NONE) {
......@@ -345,6 +343,14 @@ void CrOSComponentInstaller::FinishInstall(const std::string& name,
FROM_HERE,
base::BindOnce(std::move(load_callback),
ReportError(Error::INSTALL_FAILURE), base::FilePath()));
} else if (!IsCompatible(name)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(load_callback),
ReportError(update_policy == UpdatePolicy::kSkip
? Error::NOT_FOUND
: Error::COMPATIBILITY_CHECK_FAILED),
base::FilePath()));
} else if (mount_policy == MountPolicy::kMount) {
LoadInternal(name, std::move(load_callback));
} else {
......@@ -357,22 +363,14 @@ void CrOSComponentInstaller::FinishInstall(const std::string& name,
void CrOSComponentInstaller::LoadInternal(const std::string& name,
LoadCallback load_callback) {
const base::FilePath path = GetCompatiblePath(name);
// path is empty if no compatible component is available to load.
if (!path.empty()) {
chromeos::DBusThreadManager::Get()
->GetImageLoaderClient()
->LoadComponentAtPath(
name, path,
base::BindOnce(&CrOSComponentInstaller::FinishLoad,
base::Unretained(this), std::move(load_callback),
base::TimeTicks::Now(), name));
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(load_callback),
ReportError(Error::COMPATIBILITY_CHECK_FAILED),
base::FilePath()));
}
DCHECK(!path.empty());
chromeos::DBusThreadManager::Get()
->GetImageLoaderClient()
->LoadComponentAtPath(
name, path,
base::BindOnce(&CrOSComponentInstaller::FinishLoad,
base::Unretained(this), std::move(load_callback),
base::TimeTicks::Now(), name));
}
void CrOSComponentInstaller::FinishLoad(LoadCallback load_callback,
......@@ -398,9 +396,8 @@ void CrOSComponentInstaller::FinishLoad(LoadCallback load_callback,
void CrOSComponentInstaller::RegisterN(
const std::vector<ComponentConfig>& configs) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
ComponentUpdateService* updater = g_browser_process->component_updater();
for (const auto& config : configs) {
Register(updater, config, base::OnceClosure());
Register(config, base::OnceClosure());
}
}
......
......@@ -76,8 +76,8 @@ class CrOSComponentInstallerPolicy : public ComponentInstallerPolicy {
// This class contains functions used to register and install a component.
class CrOSComponentInstaller : public CrOSComponentManager {
public:
explicit CrOSComponentInstaller(
std::unique_ptr<MetadataTable> metadata_table);
CrOSComponentInstaller(std::unique_ptr<MetadataTable> metadata_table,
ComponentUpdateService* component_updater);
~CrOSComponentInstaller() override;
// CrOSComponentManager:
......@@ -111,21 +111,18 @@ class CrOSComponentInstaller : public CrOSComponentManager {
FRIEND_TEST_ALL_PREFIXES(CrOSComponentInstallerTest, CompatibleCrOSComponent);
// Registers a component with a dedicated ComponentUpdateService instance.
void Register(ComponentUpdateService* cus,
const ComponentConfig& config,
void Register(const ComponentConfig& config,
base::OnceClosure register_callback);
// Installs a component with a dedicated ComponentUpdateService instance.
void Install(ComponentUpdateService* cus,
const std::string& name,
void Install(const std::string& name,
UpdatePolicy update_policy,
MountPolicy mount_policy,
LoadCallback load_callback);
// Calls OnDemandUpdate to install the component right after being registered.
// |id| is the component id generated from its sha2 hash.
void StartInstall(ComponentUpdateService* cus,
const std::string& name,
void StartInstall(const std::string& name,
const std::string& id,
UpdatePolicy update_policy,
update_client::Callback install_callback);
......@@ -133,6 +130,7 @@ class CrOSComponentInstaller : public CrOSComponentManager {
// Calls LoadInternal to load the installed component.
void FinishInstall(const std::string& name,
MountPolicy mount_policy,
UpdatePolicy update_policy,
LoadCallback load_callback,
update_client::Error error);
......@@ -162,6 +160,8 @@ class CrOSComponentInstaller : public CrOSComponentManager {
// Table storing metadata (installs, usage, etc.).
std::unique_ptr<MetadataTable> metadata_table_;
ComponentUpdateService* const component_updater_;
DISALLOW_COPY_AND_ASSIGN(CrOSComponentInstaller);
};
......
......@@ -2,45 +2,350 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/test/scoped_path_override.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/browser_process_platform_part_chromeos.h"
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
#include "chrome/browser/component_updater/metadata_table_chromeos.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/chromeos_paths.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_image_loader_client.h"
#include "components/component_updater/mock_component_updater_service.h"
#include "components/update_client/utils.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace component_updater {
class CrOSMockComponentUpdateService
: public component_updater::MockComponentUpdateService {
namespace {
// Information about the component used in tests (not test-only; the component
// is OK to change, as long as its config still satisfies test assumptions).
constexpr char kTestComponentName[] = "demo-mode-resources";
constexpr char kTestComponentValidMinEnvVersion[] = "1.0";
constexpr char kTestComponentInvalidMinEnvVersion[] = "0.0.1";
constexpr char kTestComponentMountPath[] =
"/run/imageloader/demo-mode-resources";
MATCHER_P(CrxComponentWithName, name, "") {
return arg.name == name;
}
// Used as a callback to CrOSComponentManager::Load callback - it records the
// callback params to |result_out| and |mount_path_out|.
void RecordLoadResult(base::Optional<CrOSComponentManager::Error>* result_out,
base::FilePath* mount_path_out,
CrOSComponentManager::Error reported_result,
const base::FilePath& reported_mount_path) {
*result_out = reported_result;
*mount_path_out = reported_mount_path;
}
// Wraps update_client::Callback inside update_client::CrxInstaller::Install
// callback. It expects a success result to be reported.
void WrapInstallerCallback(update_client::Callback callback,
const update_client::CrxInstaller::Result& result) {
EXPECT_EQ(0, result.error);
std::move(callback).Run(update_client::Error::NONE);
}
class TestUpdater : public OnDemandUpdater {
public:
CrOSMockComponentUpdateService() {}
~CrOSMockComponentUpdateService() override {}
TestUpdater() = default;
~TestUpdater() override = default;
// Whether has a pending update request (either foreground or background).
bool HasPendingUpdate(const std::string& name) {
return base::ContainsKey(background_updates_, name) ||
base::ContainsKey(foreground_updates_, name);
}
// Finishes a foreground update request. Returns false if there is no pending
// foreground update request for the component.
// |name|: Component name.
// |error|: The error code that the update request should report.
// |unpacked_path|: On success, the path from which the component should be
// installed.
bool FinishForegroundUpdate(const std::string& name,
update_client::Error error,
const base::FilePath& unpacked_path) {
return FinishUpdate(name, error, unpacked_path, &foreground_updates_);
}
// Finishes a background update request. Returns false if there is no pending
// foreground update request for the component.
// |name|: Component name.
// |error|: The error code that the update request should report.
// |unpacked_path|: On success, the path from which the component should be
// installed.
bool FinishBackgroundUpdate(const std::string& name,
update_client::Error error,
const base::FilePath& unpacked_path) {
return FinishUpdate(name, error, unpacked_path, &background_updates_);
}
// Registers a CRX component for updates.
bool RegisterComponent(const update_client::CrxComponent& component) {
component_installers_[component.name] = component.installer;
component_id_to_name_[update_client::GetCrxComponentID(component)] =
component.name;
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(CrOSMockComponentUpdateService);
// OnDemandUpdater:
void OnDemandUpdate(const std::string& id,
OnDemandUpdater::Priority priority,
Callback callback) override {
const std::string& name = component_id_to_name_[id];
ASSERT_FALSE(name.empty());
// Technically, this is a supported use case for background updates, but not
// needed for this tests.
ASSERT_FALSE(HasPendingUpdate(name));
if (priority == OnDemandUpdater::Priority::BACKGROUND) {
background_updates_.emplace(name, std::move(callback));
} else {
foreground_updates_.emplace(name, std::move(callback));
}
}
// Shared implementation for FinishForegroundUpdate() and
// FinishBackgroundUpdate().
bool FinishUpdate(const std::string& name,
update_client::Error error,
const base::FilePath& unpacked_path,
std::map<std::string, Callback>* updates) {
auto it = updates->find(name);
if (it == updates->end())
return false;
Callback callback = std::move(it->second);
updates->erase(it);
if (error != update_client::Error::NONE) {
std::move(callback).Run(error);
return true;
}
scoped_refptr<update_client::CrxInstaller> installer =
component_installers_[name];
if (!installer)
return false;
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock()},
base::BindOnce(
&update_client::CrxInstaller::Install, installer, unpacked_path, "",
base::BindOnce(&WrapInstallerCallback, std::move(callback))));
return true;
}
// Pending background updates per component.
std::map<std::string, Callback> background_updates_;
// Pending foreground updates per component.
std::map<std::string, Callback> foreground_updates_;
// Maps a component name to the component's registered CRX installer.
std::map<std::string, scoped_refptr<update_client::CrxInstaller>>
component_installers_;
// Maps a registered component ID to the component name.
std::map<std::string, std::string> component_id_to_name_;
DISALLOW_COPY_AND_ASSIGN(TestUpdater);
};
class CrOSComponentInstallerTest : public PlatformTest {
} // namespace
class CrOSComponentInstallerTest : public testing::Test {
public:
CrOSComponentInstallerTest() {}
void SetUp() override { PlatformTest::SetUp(); }
CrOSComponentInstallerTest()
: user_manager_(std::make_unique<chromeos::FakeChromeUserManager>()) {}
void SetUp() override {
ASSERT_TRUE(base_component_paths_.CreateUniqueTempDir());
preinstalled_cros_components_ = base_component_paths_.GetPath()
.AppendASCII("preinstalled")
.AppendASCII("cros-components");
preinstalled_components_path_override_ =
std::make_unique<base::ScopedPathOverride>(
chromeos::DIR_PREINSTALLED_COMPONENTS,
preinstalled_cros_components_.DirName());
user_cros_components_ =
base_component_paths_.GetPath().AppendASCII("user").AppendASCII(
"cros-components");
user_components_path_override_ = std::make_unique<base::ScopedPathOverride>(
chrome::DIR_USER_DATA, user_cros_components_.DirName());
tmp_unpack_dir_ = base_component_paths_.GetPath().AppendASCII("tmp_unpack");
auto fake_image_loader_client =
std::make_unique<chromeos::FakeImageLoaderClient>();
image_loader_client_ = fake_image_loader_client.get();
chromeos::DBusThreadManager::GetSetterForTesting()->SetImageLoaderClient(
std::move(fake_image_loader_client));
}
void TearDown() override {
image_loader_client_ = nullptr;
chromeos::DBusThreadManager::Shutdown();
preinstalled_components_path_override_.reset();
user_components_path_override_.reset();
}
protected:
void RunUntilIdle() {
scoped_task_environment_.RunUntilIdle();
base::RunLoop().RunUntilIdle();
// Gets expected path for a user installed component with a specific version.
base::FilePath GetInstalledComponentPath(const std::string& name,
const std::string& version) {
return user_cros_components_.AppendASCII(name).AppendASCII(version);
}
// Creates a fake "user" installed component.
// On success, it returns the path at which the component was created, nullopt
// otherwise.
base::Optional<base::FilePath> CreateInstalledComponent(
const std::string& name,
const std::string& version,
const std::string& min_env_version) {
return CreateComponentAtPath(GetInstalledComponentPath(name, version), name,
version, min_env_version);
}
// Creates a fake component at a pre-installed component path.
// On success, it returns the path at which the component was created, nullopt
// otherwise.
base::Optional<base::FilePath> CreatePreinstalledComponent(
const std::string& name,
const std::string& version,
const std::string& min_env_version) {
return CreateComponentAtPath(
preinstalled_cros_components_.AppendASCII(name), name, version,
min_env_version);
}
// Creates a fake component at a temporary path from which the component will
// be installed as a user-installed component by the test OnDemandUpdater.
// On success, it returns the path at which the component was created, nullopt
// otherwise.
base::Optional<base::FilePath> CreateUnpackedComponent(
const std::string& name,
const std::string& version,
const std::string& min_env_version) {
return CreateComponentAtPath(
tmp_unpack_dir_.AppendASCII(name).AppendASCII(version), name, version,
min_env_version);
}
// Creates a mock ComponentUpdateService. It sets the service up to expect a
// single registration request for the component |component_name|, and to
// redirect on-demand update requests to |updater|.
std::unique_ptr<MockComponentUpdateService>
CreateUpdateServiceForSingleRegistration(const std::string& component_name,
TestUpdater* updater) {
auto service = std::make_unique<MockComponentUpdateService>();
EXPECT_CALL(*service,
RegisterComponent(CrxComponentWithName(component_name)))
.Times(1)
.WillOnce(testing::Invoke(updater, &TestUpdater::RegisterComponent));
EXPECT_CALL(*service, GetOnDemandUpdater())
.WillRepeatedly(testing::ReturnRef(*updater));
return service;
}
void RunUntilIdle() { thread_bundle_.RunUntilIdle(); }
chromeos::FakeImageLoaderClient* image_loader_client() {
return image_loader_client_;
}
// Verify that cros_component_manager successfully loaded a component
// |component_name|.
// |load_result|: The result reported by CrOSComponentManager::Load().
// |component_install_path|: The path at which the component is expected to be
// installed.
void VerifyComponentLoaded(
const CrOSComponentManager& cros_component_manager,
const std::string& component_name,
base::Optional<CrOSComponentManager::Error> load_result,
const base::FilePath& component_install_path) {
ASSERT_TRUE(load_result.has_value());
ASSERT_EQ(CrOSComponentManager::Error::NONE, load_result.value());
EXPECT_EQ(component_install_path,
cros_component_manager.GetCompatiblePath(component_name));
EXPECT_TRUE(image_loader_client()->IsLoaded(component_name));
EXPECT_EQ(component_install_path,
image_loader_client()->GetComponentInstallPath(component_name));
}
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
// Creates a fake component at the specified path. Returns the target path on
// success, nullopt otherwise.
base::Optional<base::FilePath> CreateComponentAtPath(
const base::FilePath& path,
const std::string& name,
const std::string& version,
const std::string& min_env_version) {
if (!base::CreateDirectory(path))
return base::nullopt;
const std::string manifest_template = R"({
"name": "%s",
"version": "%s",
"min_env_version": "%s"
})";
const std::string manifest =
base::StringPrintf(manifest_template.c_str(), name.c_str(),
version.c_str(), min_env_version.c_str());
if (base::WriteFile(path.AppendASCII("manifest.json"), manifest.data(),
manifest.size()) != static_cast<int>(manifest.size())) {
return base::nullopt;
}
return base::make_optional(path);
}
content::TestBrowserThreadBundle thread_bundle_;
user_manager::ScopedUserManager user_manager_;
// Image loader client that is active during the test. Owned by
// chromeos::DBusThreadManager.
chromeos::FakeImageLoaderClient* image_loader_client_ = nullptr;
base::ScopedTempDir base_component_paths_;
std::unique_ptr<base::ScopedPathOverride>
preinstalled_components_path_override_;
base::FilePath preinstalled_cros_components_;
std::unique_ptr<base::ScopedPathOverride> user_components_path_override_;
base::FilePath user_cros_components_;
base::FilePath tmp_unpack_dir_;
DISALLOW_COPY_AND_ASSIGN(CrOSComponentInstallerTest);
};
......@@ -54,7 +359,8 @@ class MockCrOSComponentInstallerPolicy : public CrOSComponentInstallerPolicy {
};
TEST_F(CrOSComponentInstallerTest, CompatibleCrOSComponent) {
component_updater::CrOSComponentInstaller cros_component_manager(nullptr);
component_updater::CrOSComponentInstaller cros_component_manager(nullptr,
nullptr);
const std::string kComponent = "a";
EXPECT_FALSE(cros_component_manager.IsCompatible(kComponent));
......@@ -105,15 +411,401 @@ TEST_F(CrOSComponentInstallerTest, IsCompatibleOrNot) {
}
TEST_F(CrOSComponentInstallerTest, RegisterComponent) {
std::unique_ptr<CrOSMockComponentUpdateService> cus(
new CrOSMockComponentUpdateService());
auto cus = std::make_unique<MockComponentUpdateService>();
ComponentConfig config{
"star-cups-driver", "1.1",
"6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"};
EXPECT_CALL(*cus, RegisterComponent(testing::_)).Times(1);
component_updater::CrOSComponentInstaller cros_component_manager(nullptr);
cros_component_manager.Register(cus.get(), config, base::OnceClosure());
component_updater::CrOSComponentInstaller cros_component_manager(nullptr,
cus.get());
cros_component_manager.Register(config, base::OnceClosure());
RunUntilIdle();
}
TEST_F(CrOSComponentInstallerTest, LoadPreinstalledComponent_Skip_Mount) {
base::Optional<base::FilePath> install_path = CreatePreinstalledComponent(
kTestComponentName, "1.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kSkip,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
install_path.value());
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest,
LoadInstalledComponentWhenOlderPreinstalledVersionExists_Skip_Mount) {
base::Optional<base::FilePath> preinstalled_path =
CreatePreinstalledComponent(kTestComponentName, "1.0",
kTestComponentValidMinEnvVersion);
ASSERT_TRUE(preinstalled_path.has_value());
base::Optional<base::FilePath> install_path = CreateInstalledComponent(
kTestComponentName, "2.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kSkip,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
install_path.value());
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest, LoadInstalledComponent) {
base::Optional<base::FilePath> install_path = CreateInstalledComponent(
kTestComponentName, "2.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kSkip,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
install_path.value());
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest, LoadNonInstalledComponent_Skip_Mount) {
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kSkip,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_FALSE(updater.HasPendingUpdate(kTestComponentName));
ASSERT_TRUE(load_result.has_value());
EXPECT_EQ(CrOSComponentManager::Error::NOT_FOUND, load_result.value());
EXPECT_TRUE(mount_path.empty());
EXPECT_TRUE(
cros_component_manager.GetCompatiblePath(kTestComponentName).empty());
EXPECT_FALSE(image_loader_client()->IsLoaded(kTestComponentName));
}
TEST_F(CrOSComponentInstallerTest, LoadObsoleteInstalledComponent_Skip_Mount) {
base::Optional<base::FilePath> old_install_path = CreateInstalledComponent(
kTestComponentName, "0.5", kTestComponentInvalidMinEnvVersion);
ASSERT_TRUE(old_install_path.has_value());
base::Optional<base::FilePath> old_preinstall_path = CreateInstalledComponent(
kTestComponentName, "0.5", kTestComponentInvalidMinEnvVersion);
ASSERT_TRUE(old_preinstall_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kSkip,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_FALSE(updater.HasPendingUpdate(kTestComponentName));
ASSERT_TRUE(load_result.has_value());
EXPECT_EQ(CrOSComponentManager::Error::NOT_FOUND, load_result.value());
EXPECT_TRUE(mount_path.empty());
EXPECT_TRUE(
cros_component_manager.GetCompatiblePath(kTestComponentName).empty());
EXPECT_FALSE(image_loader_client()->IsLoaded(kTestComponentName));
}
TEST_F(CrOSComponentInstallerTest, LoadNonInstalledComponent_DontForce_Mount) {
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kDontForce,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
base::Optional<base::FilePath> unpacked_path = CreateUnpackedComponent(
kTestComponentName, "2.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(unpacked_path.has_value());
ASSERT_TRUE(updater.FinishForegroundUpdate(
kTestComponentName, update_client::Error::NONE, unpacked_path.value()));
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
GetInstalledComponentPath(kTestComponentName, "2.0"));
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest,
LoadComponentWithInstallFail_DontForce_Mount) {
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kDontForce,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
ASSERT_TRUE(updater.FinishForegroundUpdate(
kTestComponentName, update_client::Error::SERVICE_ERROR,
base::FilePath()));
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
ASSERT_TRUE(load_result.has_value());
EXPECT_EQ(CrOSComponentManager::Error::INSTALL_FAILURE, load_result.value());
EXPECT_TRUE(mount_path.empty());
EXPECT_TRUE(
cros_component_manager.GetCompatiblePath(kTestComponentName).empty());
EXPECT_FALSE(image_loader_client()->IsLoaded(kTestComponentName));
}
TEST_F(CrOSComponentInstallerTest,
LoadWithObsoleteInstalledComponent_DontForce_Mount) {
base::Optional<base::FilePath> old_install_path = CreateInstalledComponent(
kTestComponentName, "0.5", kTestComponentInvalidMinEnvVersion);
ASSERT_TRUE(old_install_path.has_value());
base::Optional<base::FilePath> old_preinstall_path =
CreatePreinstalledComponent(kTestComponentName, "0.5",
kTestComponentInvalidMinEnvVersion);
ASSERT_TRUE(old_preinstall_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kDontForce,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
base::Optional<base::FilePath> unpacked_path = CreateUnpackedComponent(
kTestComponentName, "2.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(unpacked_path.has_value());
ASSERT_TRUE(updater.FinishForegroundUpdate(
kTestComponentName, update_client::Error::NONE, unpacked_path.value()));
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
GetInstalledComponentPath(kTestComponentName, "2.0"));
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest, RegisterAllRegistersInstalledComponent) {
base::Optional<base::FilePath> install_path = CreateInstalledComponent(
kTestComponentName, "1.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
cros_component_manager.RegisterInstalled();
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
EXPECT_EQ(install_path,
cros_component_manager.GetCompatiblePath(kTestComponentName));
EXPECT_FALSE(image_loader_client()->IsLoaded(kTestComponentName));
}
TEST_F(CrOSComponentInstallerTest, RegisterAllIgnoresPrenstalledComponent) {
base::Optional<base::FilePath> preinstall_path = CreatePreinstalledComponent(
kTestComponentName, "1.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(preinstall_path.has_value());
auto update_service = std::make_unique<MockComponentUpdateService>();
EXPECT_CALL(*update_service, RegisterComponent(testing::_)).Times(0);
EXPECT_CALL(*update_service, GetOnDemandUpdater()).Times(0);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
cros_component_manager.RegisterInstalled();
RunUntilIdle();
EXPECT_TRUE(
cros_component_manager.GetCompatiblePath(kTestComponentName).empty());
EXPECT_FALSE(image_loader_client()->IsLoaded(kTestComponentName));
}
TEST_F(CrOSComponentInstallerTest,
LoadInstalledComponentAfterRegisterInstalled) {
base::Optional<base::FilePath> install_path = CreateInstalledComponent(
kTestComponentName, "1.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
std::unique_ptr<MockComponentUpdateService> update_service =
CreateUpdateServiceForSingleRegistration(kTestComponentName, &updater);
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
cros_component_manager.RegisterInstalled();
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
EXPECT_EQ(install_path.value(),
cros_component_manager.GetCompatiblePath(kTestComponentName));
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kDontForce,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
install_path.value());
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
TEST_F(CrOSComponentInstallerTest,
LoadInstalledComponentConcurrentWithRegisterInstalled) {
base::Optional<base::FilePath> install_path = CreateInstalledComponent(
kTestComponentName, "1.0", kTestComponentValidMinEnvVersion);
ASSERT_TRUE(install_path.has_value());
image_loader_client()->SetMountPathForComponent(
kTestComponentName, base::FilePath(kTestComponentMountPath));
TestUpdater updater;
auto update_service = std::make_unique<MockComponentUpdateService>();
EXPECT_CALL(*update_service,
RegisterComponent(CrxComponentWithName(kTestComponentName)))
.Times(2)
.WillRepeatedly(
testing::Invoke(&updater, &TestUpdater::RegisterComponent));
EXPECT_CALL(*update_service, GetOnDemandUpdater())
.WillRepeatedly(testing::ReturnRef(updater));
component_updater::CrOSComponentInstaller cros_component_manager(
nullptr, update_service.get());
cros_component_manager.RegisterInstalled();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
base::Optional<CrOSComponentManager::Error> load_result;
base::FilePath mount_path;
cros_component_manager.Load(
kTestComponentName, CrOSComponentManager::MountPolicy::kMount,
CrOSComponentManager::UpdatePolicy::kDontForce,
base::BindOnce(&RecordLoadResult, &load_result, &mount_path));
RunUntilIdle();
EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName));
VerifyComponentLoaded(cros_component_manager, kTestComponentName, load_result,
install_path.value());
EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path);
}
} // namespace component_updater
......@@ -26,6 +26,8 @@ class CrOSComponentManager {
INSTALL_FAILURE = 2, // update_client fails to install component.
MOUNT_FAILURE = 3, // Component can not be mounted.
COMPATIBILITY_CHECK_FAILED = 4, // Compatibility check failed.
NOT_FOUND = 5, // A component installation was not found - reported for
// load requests with kSkip update policy.
ERROR_MAX
};
......
......@@ -121,7 +121,11 @@ void ChromeUnitTestSuite::InitializeProviders() {
content::RegisterPathProvider();
ui::RegisterPathProvider();
component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS,
#if defined(OS_CHROMEOS)
chromeos::DIR_PREINSTALLED_COMPONENTS,
#else
chrome::DIR_INTERNAL_PLUGINS,
#endif
chrome::DIR_USER_DATA);
#if defined(OS_CHROMEOS)
......
......@@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
namespace chromeos {
......@@ -25,12 +26,29 @@ void FakeImageLoaderClient::SetMountPathForComponent(
mount_paths_[component_name] = mount_path;
}
bool FakeImageLoaderClient::IsLoaded(const std::string& name) const {
return base::ContainsKey(loaded_components_, name);
}
base::FilePath FakeImageLoaderClient::GetComponentInstallPath(
const std::string& name) const {
if (!IsLoaded(name))
return base::FilePath();
const auto it = component_install_paths_.find(name);
if (it == component_install_paths_.end())
return base::FilePath();
return it->second;
}
void FakeImageLoaderClient::RegisterComponent(
const std::string& name,
const std::string& version,
const std::string& component_folder_abs_path,
DBusMethodCallback<bool> callback) {
registered_components_[name] = version;
component_install_paths_[name] =
base::FilePath(component_folder_abs_path).AppendASCII(version);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::make_optional(true)));
......@@ -53,6 +71,7 @@ void FakeImageLoaderClient::LoadComponent(
return;
}
loaded_components_.insert(name);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
......@@ -71,6 +90,10 @@ void FakeImageLoaderClient::LoadComponentAtPath(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
return;
}
loaded_components_.insert(name);
component_install_paths_[name] = path;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
base::make_optional(mount_path_it->second)));
......@@ -79,6 +102,7 @@ void FakeImageLoaderClient::LoadComponentAtPath(
void FakeImageLoaderClient::RemoveComponent(const std::string& name,
DBusMethodCallback<bool> callback) {
registered_components_.erase(name);
component_install_paths_.erase(name);
UnmountComponent(name, std::move(callback));
}
......@@ -99,7 +123,8 @@ void FakeImageLoaderClient::RequestComponentVersion(
void FakeImageLoaderClient::UnmountComponent(
const std::string& name,
DBusMethodCallback<bool> callback) {
mount_paths_.erase(name);
loaded_components_.erase(name);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::make_optional(true)));
......
......@@ -6,6 +6,7 @@
#define CHROMEOS_DBUS_FAKE_IMAGE_LOADER_CLIENT_H_
#include <map>
#include <set>
#include <string>
#include "base/macros.h"
......@@ -27,6 +28,17 @@ class CHROMEOS_EXPORT FakeImageLoaderClient : public ImageLoaderClient {
void SetMountPathForComponent(const std::string& component_name,
const base::FilePath& mount_path);
// Returns whether the component with the specified name was loaded.
bool IsLoaded(const std::string& name) const;
// Returns the file path from which the specified component was loaded.
// For component loaded using LoadComponent this will be the component path
// registered for the component in RegisterComponent.
// For component loaded using LoadComponentAtPath, it will be the path passed
// into the load method.
// Returns empty file path if the component is not loaded at the time.
base::FilePath GetComponentInstallPath(const std::string& name) const;
// DBusClient override.
void Init(dbus::Bus* dbus) override {}
......@@ -50,7 +62,7 @@ class CHROMEOS_EXPORT FakeImageLoaderClient : public ImageLoaderClient {
DBusMethodCallback<bool> callback) override;
private:
// Maps registered component name to its registered varsion.
// Maps registered component name to its registered version.
std::map<std::string, std::string> registered_components_;
// Maps component names to paths to which they should be mounted.
......@@ -58,6 +70,12 @@ class CHROMEOS_EXPORT FakeImageLoaderClient : public ImageLoaderClient {
// called, and removed by a later call to UnmountComponent().
std::map<std::string, base::FilePath> mount_paths_;
// Set of loaded components.
std::set<std::string> loaded_components_;
// Maps a loaded component to the path from which it was loaded.
std::map<std::string, base::FilePath> component_install_paths_;
DISALLOW_COPY_AND_ASSIGN(FakeImageLoaderClient);
};
......
......@@ -8941,6 +8941,7 @@ Called by update_net_error_codes.py.-->
<int value="2" label="INSTALL_FAILURE"/>
<int value="3" label="MOUNT_FAILURE"/>
<int value="4" label="COMPATIBILITY_CHECK_FAILED"/>
<int value="5" label="NOT_FOUND"/>
</enum>
<enum name="CrosDictationToggleDictationMethod">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment