blob: cef46739637cd32b65cea323b02c81b56715ce4c [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/browser_data_migrator.h"
#include <string>
#include "ash/components/login/auth/user_context.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ash/crosapi/move_migrator.h"
#include "chrome/browser/ash/login/existing_user_controller.h"
#include "chrome/browser/ash/login/login_manager_test.h"
#include "chrome/browser/ash/login/test/local_state_mixin.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/browser_process.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_launcher.h"
namespace ash {
namespace {
constexpr char kUserIdHash[] = "abcdefg";
// As defined in /ash/components/login/auth/stub_authenticator.cc
static const char kUserIdHashSuffix[] = "-hash";
} // namespace
// Used to test whether migration gets triggered during the signin flow.
// Concretely it tests `MaybeRestartToMigrate()` called from
// `UserSessionManager::DoBrowserLaunchInternal()` and
// `MaybeForceResumeMoveMigration()` called from
// `ExistingUserController::ContinueAuthSuccessAfterResumeAttempt()`.
class BrowserDataMigratorOnSignIn : public ash::LoginManagerTest {
public:
BrowserDataMigratorOnSignIn() = default;
BrowserDataMigratorOnSignIn(BrowserDataMigratorOnSignIn&) = delete;
BrowserDataMigratorOnSignIn& operator=(BrowserDataMigratorOnSignIn&) = delete;
~BrowserDataMigratorOnSignIn() override = default;
// ash::LoginManagerTest:
void SetUp() override {
login_manager_mixin_.AppendRegularUsers(1);
ash::LoginManagerTest::SetUp();
}
bool LoginAsRegularUser() {
ExistingUserController* controller =
ExistingUserController::current_controller();
if (!controller) {
return false;
}
const auto& test_user_info = login_manager_mixin_.users()[0];
const UserContext user_context =
CreateUserContext(test_user_info.account_id, kPassword);
SetExpectedCredentials(user_context);
controller->Login(user_context, SigninSpecifics());
return true;
}
void SetUpInProcessBrowserTestFixture() override {
SessionManagerClient::InitializeFakeInMemory();
}
protected:
LoginManagerMixin login_manager_mixin_{&mixin_host_};
};
class BrowserDataMigratorCopyMigrateOnSignIn
: public BrowserDataMigratorOnSignIn {
public:
BrowserDataMigratorCopyMigrateOnSignIn() = default;
BrowserDataMigratorCopyMigrateOnSignIn(
BrowserDataMigratorCopyMigrateOnSignIn&) = delete;
BrowserDataMigratorCopyMigrateOnSignIn& operator=(
BrowserDataMigratorCopyMigrateOnSignIn&) = delete;
~BrowserDataMigratorCopyMigrateOnSignIn() override = default;
void SetUp() override {
feature_list_.InitWithFeatures(
{ash::features::kLacrosSupport,
ash::features::kLacrosProfileMigrationForAnyUser},
{});
BrowserDataMigratorOnSignIn::SetUp();
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Check that migration is triggered from signin flow if Lacros is enabled.
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorCopyMigrateOnSignIn,
MigrateOnSignIn) {
base::RunLoop run_loop;
ScopedRestartAttemptForTesting scoped_restart_attempt(
base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
LoginAsRegularUser();
run_loop.Run();
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
// Migration should be triggered in copy mode and not move mode.
EXPECT_FALSE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
};
class BrowserDataMigratorMoveMigrateOnSignInByPolicy
: public BrowserDataMigratorOnSignIn {
public:
BrowserDataMigratorMoveMigrateOnSignInByPolicy() = default;
BrowserDataMigratorMoveMigrateOnSignInByPolicy(
BrowserDataMigratorMoveMigrateOnSignInByPolicy&) = delete;
BrowserDataMigratorMoveMigrateOnSignInByPolicy& operator=(
BrowserDataMigratorMoveMigrateOnSignInByPolicy&) = delete;
~BrowserDataMigratorMoveMigrateOnSignInByPolicy() override = default;
void SetUp() override {
feature_list_.InitWithFeatures(
{ash::features::kLacrosProfileMigrationForAnyUser}, {});
BrowserDataMigratorOnSignIn::SetUp();
}
void SetLacrosAvailability(
crosapi::browser_util::LacrosAvailability lacros_availability) {
policy::PolicyMap policy;
policy.Set(
policy::key::kLacrosAvailability, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(GetLacrosAvailabilityPolicyName(lacros_availability)),
/*external_data_fetcher=*/nullptr);
crosapi::browser_util::CacheLacrosAvailability(policy);
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Enabling LacrosOnly by policy should trigger move migration during signin.
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorMoveMigrateOnSignInByPolicy,
MigrateOnSignIn) {
base::RunLoop run_loop;
ScopedRestartAttemptForTesting scoped_restart_attempt(
base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
SetLacrosAvailability(crosapi::browser_util::LacrosAvailability::kLacrosOnly);
LoginAsRegularUser();
run_loop.Run();
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
};
class BrowserDataMigratorMoveMigrateOnSignInByFeature
: public BrowserDataMigratorOnSignIn {
public:
BrowserDataMigratorMoveMigrateOnSignInByFeature() = default;
BrowserDataMigratorMoveMigrateOnSignInByFeature(
BrowserDataMigratorMoveMigrateOnSignInByFeature&) = delete;
BrowserDataMigratorMoveMigrateOnSignInByFeature& operator=(
BrowserDataMigratorMoveMigrateOnSignInByFeature&) = delete;
~BrowserDataMigratorMoveMigrateOnSignInByFeature() override = default;
void SetUp() override {
feature_list_.InitWithFeatures(
{ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
ash::features::kLacrosOnly,
ash::features::kLacrosProfileMigrationForAnyUser},
{});
BrowserDataMigratorOnSignIn::SetUp();
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Enabling LacrosOnly with feature flags should trigger move migration during
// signin.
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorMoveMigrateOnSignInByFeature,
MigrateOnSignIn) {
base::RunLoop run_loop;
ScopedRestartAttemptForTesting scoped_restart_attempt(
base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
LoginAsRegularUser();
run_loop.Run();
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
};
class BrowserDataMigratorResumeOnSignIn : public BrowserDataMigratorOnSignIn,
public LocalStateMixin::Delegate {
public:
BrowserDataMigratorResumeOnSignIn() = default;
BrowserDataMigratorResumeOnSignIn(BrowserDataMigratorResumeOnSignIn&) =
delete;
BrowserDataMigratorResumeOnSignIn& operator=(
BrowserDataMigratorResumeOnSignIn&) = delete;
~BrowserDataMigratorResumeOnSignIn() override = default;
// LocalStateMixin::Delegate:
void SetUpLocalState() override {
const auto& user = login_manager_mixin_.users()[0];
const std::string user_id_hash =
user.account_id.GetUserEmail() + kUserIdHashSuffix;
// Setting this pref triggers a restart to resume move migration. Check
// `BrowserDataMigratorImpl::MaybeForceResumeMoveMigration()`.
MoveMigrator::SetResumeStep(g_browser_process->local_state(), user_id_hash,
MoveMigrator::ResumeStep::kMoveLacrosItems);
}
private:
LocalStateMixin local_state_mixin_{&mixin_host_, this};
};
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorResumeOnSignIn, ForceResumeOnLogin) {
// Test `MaybeForceResumeMoveMigration()` in
// `ExistingUserController::ContinueAuthSuccessAfterResumeAttempt()`.
base::RunLoop run_loop;
ScopedRestartAttemptForTesting scoped_restart_attempt(
base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
LoginAsRegularUser();
run_loop.Run();
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
}
// Used to test whether migration gets triggered upon restart in session.
// Concretely it tests `MaybeRestartToMigrate()` or
// `MaybeForceResumeMoveMigration()` called from
// `ChromeBrowserMainPartsAsh::PreProfileInit()`. Since `PreProfileInit()` gets
// called before the body of tests are run, all the setups have to happen in
// early setup stages like `SetUp()` or `SetUpCommandLine()`.
class BrowserDataMigratorRestartInSession
: public MixinBasedInProcessBrowserTest,
public LocalStateMixin::Delegate {
public:
BrowserDataMigratorRestartInSession()
: scoped_attempt_restart_(
std::make_unique<ScopedRestartAttemptForTesting>(
base::DoNothing())) {}
BrowserDataMigratorRestartInSession(BrowserDataMigratorRestartInSession&) =
delete;
BrowserDataMigratorRestartInSession& operator=(
BrowserDataMigratorRestartInSession&) = delete;
~BrowserDataMigratorRestartInSession() override = default;
// LocalStateMixin::Delegate
void SetUpLocalState() override {
// Add `kUserIdHash`@gmail.com to kRegularUsersPref so that
// `UserManager::FindUser()` is able to find this user in
// `BrowserDataMigrator::MaybeRestartToMigrate()` and
// `BrowserDataMigrator::RestartToMigrate()`.
base::Value::List users;
users.Append(base::Value(std::string(kUserIdHash) + "@gmail.com"));
g_browser_process->local_state()->SetList(user_manager::kRegularUsersPref,
std::move(users));
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// By setting these flags, Ash is launched as if it's restarted inside a
// user session.
command_line->AppendSwitchASCII(switches::kLoginUser, kUserIdHash);
command_line->AppendSwitchASCII(switches::kLoginProfile, kUserIdHash);
MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
}
void SetUpInProcessBrowserTestFixture() override {
SessionManagerClient::InitializeFakeInMemory();
}
protected:
// Since triggering migration means calling `chrome::AttemptRestart()`, it has
// to be substituted.
std::unique_ptr<ScopedRestartAttemptForTesting> scoped_attempt_restart_;
LocalStateMixin local_state_mixin_{&mixin_host_, this};
base::test::ScopedFeatureList feature_list_;
};
class BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature
: public BrowserDataMigratorRestartInSession {
public:
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature() = default;
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature(
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature&) = delete;
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature& operator=(
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature&) = delete;
~BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature() override =
default;
void SetUp() override {
feature_list_.InitWithFeatures(
{ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
ash::features::kLacrosOnly,
ash::features::kLacrosProfileMigrationForAnyUser},
{});
BrowserDataMigratorRestartInSession::SetUp();
}
};
// Test that enabling LacrosOnly by feature flags triggers move migration during
// restart.
IN_PROC_BROWSER_TEST_F(
BrowserDataMigratorMoveMigrateOnRestartInSessionByFeature,
RunMoveMigration) {
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
}
class BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy
: public BrowserDataMigratorRestartInSession {
public:
BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy() = default;
BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy(
BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy&) = delete;
BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy& operator=(
BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy&) = delete;
~BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy() override =
default;
void SetUp() override {
feature_list_.InitAndEnableFeature(
ash::features::kLacrosProfileMigrationForAnyUser);
BrowserDataMigratorRestartInSession::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(
crosapi::browser_util::kLacrosAvailabilityPolicySwitch,
crosapi::browser_util::kLacrosAvailabilityPolicyLacrosOnly);
BrowserDataMigratorRestartInSession::SetUpCommandLine(command_line);
}
};
// Test that enabling LacrosOnly by policy triggers move migration during
// restart.
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy,
RunMoveMigration) {
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
}
class BrowserDataMigratorResumeRestartInSession
: public BrowserDataMigratorRestartInSession {
public:
BrowserDataMigratorResumeRestartInSession() = default;
BrowserDataMigratorResumeRestartInSession(
BrowserDataMigratorResumeRestartInSession&) = delete;
BrowserDataMigratorResumeRestartInSession& operator=(
BrowserDataMigratorResumeRestartInSession&) = delete;
~BrowserDataMigratorResumeRestartInSession() override = default;
// LocalStateMixin::Delegate
void SetUpLocalState() override {
// Setting this pref triggers a restart to resume move migration. Check
// `BrowserDataMigratorImpl::MaybeForceResumeMoveMigration()`.
MoveMigrator::SetResumeStep(g_browser_process->local_state(), kUserIdHash,
MoveMigrator::ResumeStep::kMoveLacrosItems);
BrowserDataMigratorRestartInSession::SetUpLocalState();
}
};
IN_PROC_BROWSER_TEST_F(BrowserDataMigratorResumeRestartInSession,
ResumeMigration) {
// Test `MaybeForceResumeMoveMigration()` in
// `ChromeBrowserMainPartsAsh::PreProfileInit()`.
EXPECT_TRUE(
FakeSessionManagerClient::Get()->request_browser_data_migration_called());
EXPECT_TRUE(FakeSessionManagerClient::Get()
->request_browser_data_migration_for_move_called());
}
} // namespace ash