| // 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 "chrome/browser/component_updater/cros_component_installer_chromeos.h" |
| |
| #include <map> |
| #include <optional> |
| #include <utility> |
| |
| #include "ash/constants/ash_paths.h" |
| #include "base/containers/contains.h" |
| #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.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/thread_pool.h" |
| #include "base/test/scoped_path_override.h" |
| #include "base/test/test_future.h" |
| #include "base/test/test_simple_task_runner.h" |
| #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" |
| #include "chrome/browser/browser_process_platform_part_ash.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/ash/components/dbus/image_loader/fake_image_loader_client.h" |
| #include "chromeos/ash/components/dbus/image_loader/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/browser_task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace component_updater { |
| |
| 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"; |
| |
| constexpr char kGrowthCampaignsName[] = "growth-campaigns"; |
| |
| 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(std::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: |
| TestUpdater() = default; |
| |
| TestUpdater(const TestUpdater&) = delete; |
| TestUpdater& operator=(const TestUpdater&) = delete; |
| |
| ~TestUpdater() override = default; |
| |
| // Whether has a pending update request (either foreground or background). |
| bool HasPendingUpdate(const std::string& name) { |
| return base::Contains(background_updates_, name) || |
| base::Contains(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 ComponentRegistration& component) { |
| component_installers_[component.name] = component.installer; |
| update_client::CrxComponent crx; |
| crx.pk_hash = component.public_key_hash; |
| component_id_to_name_[update_client::GetCrxComponentID(crx)] = |
| component.name; |
| return true; |
| } |
| |
| private: |
| // 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()); |
| if (HasPendingUpdate(name)) { |
| std::move(callback).Run(update_client::Error::UPDATE_IN_PROGRESS); |
| return; |
| } |
| |
| 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::ThreadPool::PostTask( |
| FROM_HERE, {base::MayBlock()}, |
| base::BindOnce( |
| &update_client::CrxInstaller::Install, installer, unpacked_path, "", |
| nullptr, base::DoNothing(), |
| 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_; |
| }; |
| |
| } // namespace |
| |
| class CrOSComponentInstallerTest : public testing::Test { |
| public: |
| CrOSComponentInstallerTest() |
| : user_manager_(std::make_unique<ash::FakeChromeUserManager>()) {} |
| |
| CrOSComponentInstallerTest(const CrOSComponentInstallerTest&) = delete; |
| CrOSComponentInstallerTest& operator=(const CrOSComponentInstallerTest&) = |
| delete; |
| |
| 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>( |
| ash::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"); |
| |
| ash::ImageLoaderClient::InitializeFake(); |
| image_loader_client_ = |
| static_cast<ash::FakeImageLoaderClient*>(ash::ImageLoaderClient::Get()); |
| } |
| |
| void TearDown() override { |
| image_loader_client_ = nullptr; |
| ash::ImageLoaderClient::Shutdown(); |
| preinstalled_components_path_override_.reset(); |
| user_components_path_override_.reset(); |
| } |
| |
| protected: |
| // 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. |
| std::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. |
| std::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. |
| std::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 |
| // |times| registration request for the component |component_name|, and to |
| // redirect on-demand update requests to |updater|. |
| std::unique_ptr<MockComponentUpdateService> |
| CreateUpdateServiceForMultiRegistration(const std::string& component_name, |
| TestUpdater* updater, |
| int times) { |
| auto service = std::make_unique<MockComponentUpdateService>(); |
| EXPECT_CALL(*service, |
| RegisterComponent(CrxComponentWithName(component_name))) |
| .Times(times) |
| .WillRepeatedly( |
| testing::Invoke(updater, &TestUpdater::RegisterComponent)); |
| |
| EXPECT_CALL(*service, GetOnDemandUpdater()) |
| .WillRepeatedly(testing::ReturnRef(*updater)); |
| return service; |
| } |
| |
| // 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) { |
| return CreateUpdateServiceForMultiRegistration(component_name, updater, 1); |
| } |
| |
| void RunUntilIdle() { task_environment_.RunUntilIdle(); } |
| |
| ash::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( |
| scoped_refptr<CrOSComponentManager> cros_component_manager, |
| const std::string& component_name, |
| std::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: |
| // Creates a fake component at the specified path. Returns the target path on |
| // success, nullopt otherwise. |
| std::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 std::nullopt; |
| } |
| |
| static constexpr char kManifestTemplate[] = R"({ |
| "name": "%s", |
| "version": "%s", |
| "min_env_version": "%s" |
| })"; |
| const std::string manifest = |
| base::StringPrintf(kManifestTemplate, name.c_str(), version.c_str(), |
| min_env_version.c_str()); |
| if (!base::WriteFile(path.AppendASCII("manifest.json"), manifest)) { |
| return std::nullopt; |
| } |
| |
| return std::make_optional(path); |
| } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| |
| user_manager::ScopedUserManager user_manager_; |
| |
| // Image loader client that is active during the test. |
| raw_ptr<ash::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_; |
| }; |
| |
| TEST_F(CrOSComponentInstallerTest, CompatibleCrOSComponent) { |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, nullptr); |
| |
| const std::string kComponent = "a"; |
| EXPECT_FALSE(cros_component_manager->IsCompatible(kComponent)); |
| EXPECT_EQ(cros_component_manager->GetCompatiblePath(kComponent).value(), |
| std::string()); |
| |
| const base::FilePath kPath("/component/path/v0"); |
| const base::Version kVersion = base::Version("1.0.0.0"); |
| cros_component_manager->RegisterCompatiblePath( |
| kComponent, CompatibleComponentInfo(kPath, kVersion)); |
| EXPECT_TRUE(cros_component_manager->IsCompatible(kComponent)); |
| EXPECT_EQ(cros_component_manager->GetCompatiblePath(kComponent), kPath); |
| // Make sure the version has also been updated. |
| base::test::TestFuture<const base::Version&> get_version_future; |
| cros_component_manager->GetVersion(kComponent, |
| get_version_future.GetCallback()); |
| const base::Version& result = get_version_future.Get<0>(); |
| EXPECT_EQ(result.CompareTo(kVersion), 0); |
| |
| // Unregister the version. |
| cros_component_manager->UnregisterCompatiblePath(kComponent); |
| EXPECT_FALSE(cros_component_manager->IsCompatible(kComponent)); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, CompatibilityOK) { |
| auto update_service = std::make_unique<MockComponentUpdateService>(); |
| auto installer = base::MakeRefCounted<CrOSComponentInstaller>( |
| nullptr, update_service.get()); |
| ComponentConfig config{"component", ComponentConfig::PolicyType::kEnvVersion, |
| "2.1", ""}; |
| EnvVersionInstallerPolicy policy(config, installer.get()); |
| base::Version version; |
| base::FilePath path("/path"); |
| base::Value::Dict manifest; |
| manifest.Set("min_env_version", "2.1"); |
| policy.ComponentReady(version, path, std::move(manifest)); |
| // Component is compatible and was registered. |
| EXPECT_EQ(path, installer->GetCompatiblePath("component")); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, CompatibilityMissingManifest) { |
| auto update_service = std::make_unique<MockComponentUpdateService>(); |
| auto installer = base::MakeRefCounted<CrOSComponentInstaller>( |
| nullptr, update_service.get()); |
| ComponentConfig config{"component", ComponentConfig::PolicyType::kEnvVersion, |
| "2.1", ""}; |
| EnvVersionInstallerPolicy policy(config, installer.get()); |
| base::Version version; |
| base::FilePath path("/path"); |
| base::Value::Dict manifest; |
| policy.ComponentReady(version, path, std::move(manifest)); |
| // No compatible path was registered. |
| EXPECT_EQ(base::FilePath(), installer->GetCompatiblePath("component")); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, IsCompatibleOrNot) { |
| EXPECT_TRUE(EnvVersionInstallerPolicy::IsCompatible("1.0", "1.0")); |
| EXPECT_TRUE(EnvVersionInstallerPolicy::IsCompatible("1.1", "1.0")); |
| EXPECT_FALSE(EnvVersionInstallerPolicy::IsCompatible("1.0", "1.1")); |
| EXPECT_FALSE(EnvVersionInstallerPolicy::IsCompatible("1.0", "2.0")); |
| EXPECT_FALSE(EnvVersionInstallerPolicy::IsCompatible("1.c", "1.c")); |
| EXPECT_FALSE(EnvVersionInstallerPolicy::IsCompatible("1", "1.1")); |
| EXPECT_TRUE(EnvVersionInstallerPolicy::IsCompatible("1.1.1", "1.1")); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, LacrosMinVersion) { |
| // Use a fixed version, so the test doesn't need to change as chrome |
| // versions advance. |
| LacrosInstallerPolicy::SetAshVersionForTest("10.0.0.0"); |
| |
| // Create policy object under test. |
| auto update_service = std::make_unique<MockComponentUpdateService>(); |
| auto installer = base::MakeRefCounted<CrOSComponentInstaller>( |
| nullptr, update_service.get()); |
| ComponentConfig config{"lacros-fishfood", |
| ComponentConfig::PolicyType::kLacros, "", ""}; |
| LacrosInstallerPolicy policy(config, installer.get()); |
| |
| // Simulate finding an incompatible existing install. |
| policy.ComponentReady(base::Version("8.0.0.0"), |
| base::FilePath("/lacros/8.0.0.0"), |
| /*manifest=*/base::Value::Dict()); |
| EXPECT_TRUE(installer->GetCompatiblePath("lacros-fishfood").empty()); |
| |
| policy.ComponentReady(base::Version("9.0.0.0"), |
| base::FilePath("/lacros/9.0.0.0"), |
| /*manifest=*/base::Value::Dict()); |
| EXPECT_TRUE(installer->GetCompatiblePath("lacros-fishfood").empty()); |
| |
| // Simulate finding a compatible existing install. |
| policy.ComponentReady(base::Version("10.0.0.0"), |
| base::FilePath("/lacros/10.0.0.0"), |
| /*manifest=*/base::Value::Dict()); |
| EXPECT_EQ("/lacros/10.0.0.0", |
| installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII()); |
| |
| policy.ComponentReady(base::Version("11.0.0.0"), |
| base::FilePath("/lacros/11.0.0.0"), |
| /*manifest=*/base::Value::Dict()); |
| EXPECT_EQ("/lacros/11.0.0.0", |
| installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII()); |
| |
| policy.ComponentReady(base::Version("12.0.0.0"), |
| base::FilePath("/lacros/12.0.0.0"), |
| /*manifest=*/base::Value::Dict()); |
| EXPECT_EQ("/lacros/12.0.0.0", |
| installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII()); |
| |
| LacrosInstallerPolicy::SetAshVersionForTest(nullptr); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, LacrosUpdatesIgnoreCompoenentUpdaterPolicy) { |
| auto update_service = std::make_unique<MockComponentUpdateService>(); |
| auto installer = base::MakeRefCounted<CrOSComponentInstaller>( |
| nullptr, update_service.get()); |
| ComponentConfig config{"lacros-fishfood", |
| ComponentConfig::PolicyType::kLacros, "", ""}; |
| LacrosInstallerPolicy policy(config, installer.get()); |
| |
| ASSERT_FALSE(policy.SupportsGroupPolicyEnabledComponentUpdates()); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, RegisterComponent) { |
| auto cus = std::make_unique<MockComponentUpdateService>(); |
| ComponentConfig config{ |
| "star-cups-driver", ComponentConfig::PolicyType::kEnvVersion, "1.1", |
| "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"}; |
| EXPECT_CALL(*cus, RegisterComponent(testing::_)).Times(1); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, cus.get()); |
| cros_component_manager->Register(config, base::OnceClosure()); |
| RunUntilIdle(); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, LoadPreinstalledComponent_Skip_Mount) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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) { |
| std::optional<base::FilePath> preinstalled_path = CreatePreinstalledComponent( |
| kTestComponentName, "1.0", kTestComponentValidMinEnvVersion); |
| ASSERT_TRUE(preinstalled_path.has_value()); |
| |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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) { |
| std::optional<base::FilePath> old_install_path = CreateInstalledComponent( |
| kTestComponentName, "0.5", kTestComponentInvalidMinEnvVersion); |
| ASSERT_TRUE(old_install_path.has_value()); |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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(); |
| |
| std::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, LoadNonInstalledComponent_ForceTwice) { |
| image_loader_client()->SetMountPathForComponent( |
| kTestComponentName, base::FilePath(kTestComponentMountPath)); |
| |
| TestUpdater updater; |
| std::unique_ptr<MockComponentUpdateService> update_service = |
| CreateUpdateServiceForMultiRegistration(kTestComponentName, &updater, 2); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::optional<CrOSComponentManager::Error> load_result1; |
| base::FilePath mount_path1; |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kForce, |
| base::BindOnce(&RecordLoadResult, &load_result1, &mount_path1)); |
| |
| std::optional<CrOSComponentManager::Error> load_result2; |
| base::FilePath mount_path2; |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kForce, |
| base::BindOnce(&RecordLoadResult, &load_result2, &mount_path2)); |
| RunUntilIdle(); |
| |
| std::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)); |
| |
| // Order of the load attempts is not deterministic, but one will have no error |
| // and a non-empty mount_path, the other will have error UPDATE_IN_PROGRESS |
| // and empty mount_path. |
| if (!mount_path1.empty()) { |
| VerifyComponentLoaded(cros_component_manager, kTestComponentName, |
| load_result1, |
| GetInstalledComponentPath(kTestComponentName, "2.0")); |
| EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path1); |
| // Other load should have got a UPDATE_IN_PROGRESS error. |
| ASSERT_TRUE(load_result2.has_value()); |
| EXPECT_EQ(load_result2.value(), |
| CrOSComponentManager::Error::UPDATE_IN_PROGRESS); |
| } else { |
| VerifyComponentLoaded(cros_component_manager, kTestComponentName, |
| load_result2, |
| GetInstalledComponentPath(kTestComponentName, "2.0")); |
| EXPECT_EQ(base::FilePath(kTestComponentMountPath), mount_path2); |
| // Other load should have got a UPDATE_IN_PROGRESS error. |
| ASSERT_TRUE(load_result1.has_value()); |
| EXPECT_EQ(load_result1.value(), |
| CrOSComponentManager::Error::UPDATE_IN_PROGRESS); |
| } |
| } |
| |
| 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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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) { |
| std::optional<base::FilePath> old_install_path = CreateInstalledComponent( |
| kTestComponentName, "0.5", kTestComponentInvalidMinEnvVersion); |
| ASSERT_TRUE(old_install_path.has_value()); |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::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(); |
| |
| std::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) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(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) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(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) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| cros_component_manager->RegisterInstalled(); |
| RunUntilIdle(); |
| EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName)); |
| EXPECT_EQ(install_path.value(), |
| cros_component_manager->GetCompatiblePath(kTestComponentName)); |
| |
| std::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) { |
| std::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)); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| cros_component_manager->RegisterInstalled(); |
| EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName)); |
| |
| std::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, LoadCache) { |
| std::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); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| cros_component_manager->RegisterInstalled(); |
| RunUntilIdle(); |
| EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName)); |
| EXPECT_EQ(install_path.value(), |
| cros_component_manager->GetCompatiblePath(kTestComponentName)); |
| |
| std::optional<CrOSComponentManager::Error> load_result1; |
| base::FilePath mount_path1; |
| std::optional<CrOSComponentManager::Error> load_result2; |
| base::FilePath mount_path2; |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kDontForce, |
| base::BindOnce(&RecordLoadResult, &load_result1, &mount_path1)); |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kDontForce, |
| base::BindOnce(&RecordLoadResult, &load_result2, &mount_path2)); |
| |
| auto& load_cache = cros_component_manager->GetLoadCacheForTesting(); |
| ASSERT_EQ(load_cache.size(), 1u); |
| ASSERT_EQ(load_cache.begin()->second.callbacks.size(), 1u); |
| RunUntilIdle(); |
| |
| ASSERT_TRUE(load_result1.has_value()); |
| ASSERT_TRUE(load_result2.has_value()); |
| ASSERT_EQ(load_result1.value(), load_result2.value()); |
| ASSERT_EQ(mount_path1, mount_path2); |
| ASSERT_EQ(load_cache.size(), 1u); |
| ASSERT_EQ(load_cache.begin()->second.callbacks.size(), 0u); |
| ASSERT_TRUE(load_cache.begin()->second.success.has_value()); |
| ASSERT_TRUE(load_cache.begin()->second.success.value()); |
| ASSERT_EQ(mount_path1, load_cache.begin()->second.path); |
| } |
| |
| // Tests that when the load cache is removed for a given component successive |
| // loads will load the newest installed version. |
| TEST_F(CrOSComponentInstallerTest, |
| RemovingLoadCacheEntryAllowsLoadingNewComponentVersions) { |
| // Create and register version 1.0 of an installed component. |
| std::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 = |
| CreateUpdateServiceForMultiRegistration(kTestComponentName, &updater, 2); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| cros_component_manager->RegisterInstalled(); |
| RunUntilIdle(); |
| EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName)); |
| EXPECT_EQ(install_path.value(), |
| cros_component_manager->GetCompatiblePath(kTestComponentName)); |
| |
| std::optional<CrOSComponentManager::Error> load_result1; |
| base::FilePath mount_path1; |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kDontForce, |
| base::BindOnce(&RecordLoadResult, &load_result1, &mount_path1)); |
| |
| // Loading the component should successfully load the latest installed version |
| // (1.0) and populate the load cache. |
| auto& load_cache = cros_component_manager->GetLoadCacheForTesting(); |
| EXPECT_EQ(load_cache.size(), 1u); |
| RunUntilIdle(); |
| EXPECT_TRUE(load_result1.has_value()); |
| VerifyComponentLoaded(cros_component_manager, kTestComponentName, |
| load_result1, |
| GetInstalledComponentPath(kTestComponentName, "1.0")); |
| |
| // The component manager should remove the load cache entry for the test |
| // component when requested. |
| cros_component_manager->RemoveLoadCacheEntry(kTestComponentName); |
| EXPECT_EQ(load_cache.size(), 0u); |
| |
| // Create and register version 2.0 of the same component. |
| std::optional<base::FilePath> install_path2 = CreateInstalledComponent( |
| kTestComponentName, "2.0", kTestComponentValidMinEnvVersion); |
| ASSERT_TRUE(install_path2.has_value()); |
| |
| cros_component_manager->RegisterInstalled(); |
| RunUntilIdle(); |
| EXPECT_FALSE(updater.HasPendingUpdate(kTestComponentName)); |
| EXPECT_EQ(install_path2.value(), |
| cros_component_manager->GetCompatiblePath(kTestComponentName)); |
| |
| // Loading the component should successfully load the latest installed version |
| // (2.0) and populate the load cache. |
| std::optional<CrOSComponentManager::Error> load_result2; |
| base::FilePath mount_path2; |
| cros_component_manager->Load( |
| kTestComponentName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kDontForce, |
| base::BindOnce(&RecordLoadResult, &load_result2, &mount_path2)); |
| |
| EXPECT_EQ(load_cache.size(), 1u); |
| RunUntilIdle(); |
| EXPECT_TRUE(load_result2.has_value()); |
| VerifyComponentLoaded(cros_component_manager, kTestComponentName, |
| load_result2, |
| GetInstalledComponentPath(kTestComponentName, "2.0")); |
| EXPECT_EQ(mount_path1, mount_path2); |
| } |
| |
| TEST_F(CrOSComponentInstallerTest, LoadGrowthComponent) { |
| image_loader_client()->SetMountPathForComponent( |
| kGrowthCampaignsName, |
| base::FilePath("/run/imageloader/growth-campaigns")); |
| TestUpdater updater; |
| std::unique_ptr<MockComponentUpdateService> update_service = |
| CreateUpdateServiceForSingleRegistration(kGrowthCampaignsName, &updater); |
| scoped_refptr<CrOSComponentInstaller> cros_component_manager = |
| base::MakeRefCounted<CrOSComponentInstaller>(nullptr, |
| update_service.get()); |
| |
| std::optional<CrOSComponentManager::Error> load_result; |
| base::FilePath mount_path; |
| cros_component_manager->Load( |
| kGrowthCampaignsName, CrOSComponentManager::MountPolicy::kMount, |
| CrOSComponentManager::UpdatePolicy::kDontForce, |
| base::BindOnce(&RecordLoadResult, &load_result, &mount_path)); |
| |
| RunUntilIdle(); |
| std::optional<base::FilePath> unpacked_path = CreateUnpackedComponent( |
| kGrowthCampaignsName, "1.0", kTestComponentValidMinEnvVersion); |
| ASSERT_TRUE(unpacked_path.has_value()); |
| ASSERT_TRUE(updater.FinishForegroundUpdate( |
| kGrowthCampaignsName, update_client::Error::NONE, unpacked_path.value())); |
| |
| RunUntilIdle(); |
| ASSERT_FALSE(updater.HasPendingUpdate(kGrowthCampaignsName)); |
| |
| VerifyComponentLoaded(cros_component_manager, kGrowthCampaignsName, |
| load_result, |
| GetInstalledComponentPath(kGrowthCampaignsName, "1.0")); |
| EXPECT_EQ(base::FilePath("/run/imageloader/growth-campaigns"), mount_path); |
| } |
| |
| } // namespace component_updater |