blob: bcee937facec09794ad5308e350365792f0549a2 [file] [log] [blame]
// Copyright 2020 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/ash/crosapi/browser_loader.h"
#include "base/auto_reset.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/fake_cros_component_manager.h"
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
#include "chromeos/ash/components/dbus/upstart/fake_upstart_client.h"
#include "components/component_updater/mock_component_updater_service.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h"
#include "components/update_client/update_client.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Return;
namespace crosapi {
namespace {
// Copied from browser_loader.cc
constexpr char kLacrosComponentName[] = "lacros-dogfood-dev";
constexpr char kLacrosComponentId[] = "ldobopbhiamakmncndpkeelenhdmgfhk";
constexpr char kLacrosMounterUpstartJob[] = "lacros_2dmounter";
constexpr char kLacrosUnmounterUpstartJob[] = "lacros_2dunmounter";
// This implementation of RAII for LacrosSelection is to make it easy reset
// the state between runs.
class ScopedLacrosSelectionCache {
public:
explicit ScopedLacrosSelectionCache(
browser_util::LacrosSelectionPolicy lacros_selection) {
SetLacrosSelection(lacros_selection);
}
ScopedLacrosSelectionCache(const ScopedLacrosSelectionCache&) = delete;
ScopedLacrosSelectionCache& operator=(const ScopedLacrosSelectionCache&) =
delete;
~ScopedLacrosSelectionCache() {
browser_util::ClearLacrosSelectionCacheForTest();
}
private:
void SetLacrosSelection(
browser_util::LacrosSelectionPolicy lacros_selection) {
policy::PolicyMap policy;
policy.Set(policy::key::kLacrosSelection, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(GetLacrosSelectionPolicyName(lacros_selection)),
/*external_data_fetcher=*/nullptr);
browser_util::CacheLacrosSelection(policy);
}
};
} // namespace
class BrowserLoaderTest : public testing::Test {
public:
BrowserLoaderTest() {
// Create dependencies for object under test.
component_manager_ =
base::MakeRefCounted<component_updater::FakeCrOSComponentManager>();
component_manager_->set_supported_components({kLacrosComponentName});
component_manager_->ResetComponentState(
kLacrosComponentName,
component_updater::FakeCrOSComponentManager::ComponentInfo(
component_updater::CrOSComponentManager::Error::NONE,
base::FilePath("/install/path"), base::FilePath("/mount/path")));
browser_part_ = std::make_unique<BrowserProcessPlatformPartTestApi>(
g_browser_process->platform_part());
browser_part_->InitializeCrosComponentManager(component_manager_);
browser_loader_ = std::make_unique<BrowserLoader>(
component_manager_, &mock_component_update_service_,
&fake_upstart_client_);
}
~BrowserLoaderTest() override {
browser_part_->ShutdownCrosComponentManager();
}
// Public because this is test code.
content::BrowserTaskEnvironment task_environment_;
protected:
component_updater::MockComponentUpdateService mock_component_update_service_;
scoped_refptr<component_updater::FakeCrOSComponentManager> component_manager_;
ash::FakeUpstartClient fake_upstart_client_;
std::unique_ptr<BrowserProcessPlatformPartTestApi> browser_part_;
std::unique_ptr<BrowserLoader> browser_loader_;
private:
base::AutoReset<bool> set_lacros_enabled_ =
browser_util::SetLacrosEnabledForTest(true);
};
TEST_F(BrowserLoaderTest, OnLoadSelectionQuicklyChooseRootfs) {
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosMounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Set `was_installed` to false, in order to quickly mount rootfs
// lacros-chrome.
browser_loader_->OnLoadSelection(
base::BindOnce([](const base::FilePath&, LacrosSelection selection,
base::Version version) {
EXPECT_EQ(LacrosSelection::kRootfs, selection);
}),
false);
task_environment_.RunUntilIdle();
EXPECT_TRUE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadVersionSelectionNeitherIsAvailable) {
// Use stateful when a rootfs lacros-chrome version is invalid.
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosUnmounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Pass in an invalid `base::Version`.
browser_loader_->OnLoadVersionSelection(
/*is_stateful_lacros_available=*/false,
base::BindOnce([](const base::FilePath& path, LacrosSelection selection,
base::Version version) { EXPECT_TRUE(path.empty()); }),
/*rootfs_lacros_version=*/base::Version());
task_environment_.RunUntilIdle();
EXPECT_FALSE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadVersionSelectionStatefulIsUnavailable) {
// Use rootfs when a stateful lacros-chrome version is invalid.
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosMounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Pass in an invalid `base::Version`.
browser_loader_->OnLoadVersionSelection(
/*is_stateful_lacros_available=*/false,
base::BindOnce([](const base::FilePath& path, LacrosSelection selection,
base::Version version) {
EXPECT_EQ(LacrosSelection::kRootfs, selection);
}),
/*rootfs_lacros_version=*/base::Version("2.0.0"));
task_environment_.RunUntilIdle();
EXPECT_TRUE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsUnavailable) {
std::u16string lacros_component_name =
base::UTF8ToUTF16(base::StringPiece(kLacrosComponentName));
EXPECT_CALL(mock_component_update_service_, GetComponents())
.WillOnce(Return(std::vector<component_updater::ComponentInfo>{
{kLacrosComponentId, "", lacros_component_name,
base::Version("1.0.0"), ""}}));
// Use stateful when a rootfs lacros-chrome version is invalid.
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosUnmounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Pass in an invalid `base::Version`.
browser_loader_->OnLoadVersionSelection(
/*is_stateful_lacros_available=*/true,
base::BindOnce([](const base::FilePath& path, LacrosSelection selection,
base::Version version) {
EXPECT_EQ(LacrosSelection::kStateful, selection);
}),
/*rootfs_lacros_version=*/base::Version());
task_environment_.RunUntilIdle();
EXPECT_TRUE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsNewer) {
std::u16string lacros_component_name =
base::UTF8ToUTF16(base::StringPiece(kLacrosComponentName));
EXPECT_CALL(mock_component_update_service_, GetComponents())
.WillOnce(Return(std::vector<component_updater::ComponentInfo>{
{kLacrosComponentId, "", lacros_component_name,
base::Version("1.0.0"), ""}}));
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosMounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Pass in a rootfs lacros-chrome version that is newer.
browser_loader_->OnLoadVersionSelection(
/*is_stateful_lacros_available=*/true,
base::BindOnce([](const base::FilePath& path, LacrosSelection selection,
base::Version version) {
EXPECT_EQ(LacrosSelection::kRootfs, selection);
}),
/*rootfs_lacros_version=*/base::Version("2.0.0"));
task_environment_.RunUntilIdle();
EXPECT_TRUE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsOlder) {
// Use stateful when a rootfs lacros-chrome version is older.
std::u16string lacros_component_name =
base::UTF8ToUTF16(base::StringPiece(kLacrosComponentName));
EXPECT_CALL(mock_component_update_service_, GetComponents())
.WillOnce(Return(std::vector<component_updater::ComponentInfo>{
{kLacrosComponentId, "", lacros_component_name,
base::Version("3.0.0"), ""}}));
bool callback_called = false;
fake_upstart_client_.set_start_job_cb(base::BindRepeating(
[](bool* b, const std::string& job,
const std::vector<std::string>& upstart_env) {
EXPECT_EQ(job, kLacrosUnmounterUpstartJob);
*b = true;
return true;
},
&callback_called));
// Pass in a rootfs lacros-chrome version that is older.
browser_loader_->OnLoadVersionSelection(
/*is_stateful_lacros_available=*/true,
base::BindOnce([](const base::FilePath& path, LacrosSelection selection,
base::Version version) {
EXPECT_EQ(LacrosSelection::kStateful, selection);
}),
/*rootfs_lacros_version=*/base::Version("2.0.0"));
task_environment_.RunUntilIdle();
EXPECT_TRUE(callback_called);
}
TEST_F(BrowserLoaderTest, OnLoadSelectionPolicyIsRootfs) {
ScopedLacrosSelectionCache cache(
browser_util::LacrosSelectionPolicy::kRootfs);
base::test::ScopedCommandLine command_line;
command_line.GetProcessCommandLine()->AppendSwitchASCII(
browser_util::kLacrosSelectionSwitch,
browser_util::kLacrosSelectionStateful);
base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
browser_loader_->Load(future.GetCallback<const base::FilePath&,
LacrosSelection, base::Version>());
const LacrosSelection selection = future.Get<1>();
EXPECT_EQ(selection, LacrosSelection::kRootfs);
}
TEST_F(BrowserLoaderTest, OnLoadSelectionPolicyIsStateful) {
ScopedLacrosSelectionCache cache(
browser_util::LacrosSelectionPolicy::kStateful);
base::test::ScopedCommandLine command_line;
command_line.GetProcessCommandLine()->AppendSwitchASCII(
browser_util::kLacrosSelectionSwitch,
browser_util::kLacrosSelectionRootfs);
base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
browser_loader_->Load(future.GetCallback<const base::FilePath&,
LacrosSelection, base::Version>());
const LacrosSelection selection = future.Get<1>();
EXPECT_EQ(selection, LacrosSelection::kStateful);
}
TEST_F(BrowserLoaderTest,
OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsRootfs) {
ScopedLacrosSelectionCache cache(
browser_util::LacrosSelectionPolicy::kUserChoice);
base::test::ScopedCommandLine command_line;
command_line.GetProcessCommandLine()->AppendSwitchASCII(
browser_util::kLacrosSelectionSwitch,
browser_util::kLacrosSelectionRootfs);
base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
browser_loader_->Load(future.GetCallback<const base::FilePath&,
LacrosSelection, base::Version>());
const LacrosSelection selection = future.Get<1>();
EXPECT_EQ(selection, LacrosSelection::kRootfs);
}
TEST_F(BrowserLoaderTest,
OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsStateful) {
ScopedLacrosSelectionCache cache(
browser_util::LacrosSelectionPolicy::kUserChoice);
base::test::ScopedCommandLine command_line;
command_line.GetProcessCommandLine()->AppendSwitchASCII(
browser_util::kLacrosSelectionSwitch,
browser_util::kLacrosSelectionStateful);
base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
browser_loader_->Load(future.GetCallback<const base::FilePath&,
LacrosSelection, base::Version>());
const LacrosSelection selection = future.Get<1>();
EXPECT_EQ(selection, LacrosSelection::kStateful);
}
} // namespace crosapi