blob: e0edaed2756b1f458ea83dc9fc660fe2d17f79bd [file] [log] [blame]
// 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 "ash/components/arc/arc_util.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "ash/components/arc/arc_features.h"
#include "ash/components/arc/arc_prefs.h"
#include "ash/components/arc/session/arc_vm_data_migration_status.h"
#include "ash/components/arc/test/arc_util_test_support.h"
#include "ash/constants/app_types.h"
#include "ash/test/ash_test_base.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chromeos/ash/components/dbus/upstart/fake_upstart_client.h"
#include "components/account_id/account_id.h"
#include "components/exo/shell_surface_util.h"
#include "components/prefs/testing_pref_service.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/display/types/display_constants.h"
namespace arc {
namespace {
// If an instance is created, based on the value passed to the constructor,
// EnableARC feature is enabled/disabled in the scope.
class ScopedArcFeature {
public:
explicit ScopedArcFeature(bool enabled) {
constexpr char kArcFeatureName[] = "EnableARC";
if (enabled) {
feature_list.InitFromCommandLine(kArcFeatureName, std::string());
} else {
feature_list.InitFromCommandLine(std::string(), kArcFeatureName);
}
}
ScopedArcFeature(const ScopedArcFeature&) = delete;
ScopedArcFeature& operator=(const ScopedArcFeature&) = delete;
~ScopedArcFeature() = default;
private:
base::test::ScopedFeatureList feature_list;
};
class ScopedRtVcpuFeature {
public:
ScopedRtVcpuFeature(bool dual_core_enabled, bool quad_core_enabled) {
std::vector<base::test::FeatureRef> enabled_features;
std::vector<base::test::FeatureRef> disabled_features;
if (dual_core_enabled)
enabled_features.push_back(kRtVcpuDualCore);
else
disabled_features.push_back(kRtVcpuDualCore);
if (quad_core_enabled)
enabled_features.push_back(kRtVcpuQuadCore);
else
disabled_features.push_back(kRtVcpuQuadCore);
feature_list.InitWithFeatures(enabled_features, disabled_features);
}
~ScopedRtVcpuFeature() = default;
ScopedRtVcpuFeature(const ScopedRtVcpuFeature&) = delete;
ScopedRtVcpuFeature& operator=(const ScopedRtVcpuFeature&) = delete;
private:
base::test::ScopedFeatureList feature_list;
};
// Fake user that can be created with a specified type.
class FakeUser : public user_manager::User {
public:
explicit FakeUser(user_manager::UserType user_type)
: User(AccountId::FromUserEmailGaiaId("user@test.com", "1234567890")),
user_type_(user_type) {}
FakeUser(const FakeUser&) = delete;
FakeUser& operator=(const FakeUser&) = delete;
~FakeUser() override = default;
// user_manager::User:
user_manager::UserType GetType() const override { return user_type_; }
private:
const user_manager::UserType user_type_;
};
class ArcUtilTest : public ash::AshTestBase {
public:
ArcUtilTest() { ash::UpstartClient::InitializeFake(); }
ArcUtilTest(const ArcUtilTest&) = delete;
ArcUtilTest& operator=(const ArcUtilTest&) = delete;
~ArcUtilTest() override = default;
void SetUp() override {
ash::AshTestBase::SetUp();
prefs::RegisterProfilePrefs(profile_prefs_.registry());
RemoveUpstartStartStopJobFailures();
}
void TearDown() override { ash::AshTestBase::TearDown(); }
protected:
void InjectUpstartStartJobFailure(const std::string& job_name_to_fail) {
auto* upstart_client = ash::FakeUpstartClient::Get();
upstart_client->set_start_job_cb(base::BindLambdaForTesting(
[job_name_to_fail](const std::string& job_name,
const std::vector<std::string>& env) {
// Return success unless |job_name| is |job_name_to_fail|.
return job_name != job_name_to_fail;
}));
}
void InjectUpstartStopJobFailure(const std::string& job_name_to_fail) {
auto* upstart_client = ash::FakeUpstartClient::Get();
upstart_client->set_stop_job_cb(base::BindLambdaForTesting(
[job_name_to_fail](const std::string& job_name,
const std::vector<std::string>& env) {
// Return success unless |job_name| is |job_name_to_fail|.
return job_name != job_name_to_fail;
}));
}
void StartRecordingUpstartOperations() {
auto* upstart_client = ash::FakeUpstartClient::Get();
upstart_client->set_start_job_cb(
base::BindLambdaForTesting([this](const std::string& job_name,
const std::vector<std::string>& env) {
upstart_operations_.emplace_back(job_name, true);
return true;
}));
upstart_client->set_stop_job_cb(
base::BindLambdaForTesting([this](const std::string& job_name,
const std::vector<std::string>& env) {
upstart_operations_.emplace_back(job_name, false);
return true;
}));
}
const std::vector<std::pair<std::string, bool>>& upstart_operations() const {
return upstart_operations_;
}
PrefService* profile_prefs() { return &profile_prefs_; }
private:
void RemoveUpstartStartStopJobFailures() {
auto* upstart_client = ash::FakeUpstartClient::Get();
upstart_client->set_start_job_cb(
ash::FakeUpstartClient::StartStopJobCallback());
upstart_client->set_stop_job_cb(
ash::FakeUpstartClient::StartStopJobCallback());
}
TestingPrefServiceSimple profile_prefs_;
// List of upstart operations recorded. When it's "start" the boolean is set
// to true.
std::vector<std::pair<std::string, bool>> upstart_operations_;
};
TEST_F(ArcUtilTest, IsArcAvailable_None) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arc-availability=none"});
EXPECT_FALSE(IsArcAvailable());
// If --arc-availability flag is set to "none", even if Finch experiment is
// turned on, ARC cannot be used.
{
ScopedArcFeature feature(true);
EXPECT_FALSE(IsArcAvailable());
}
}
// Test --arc-available with EnableARC feature combination.
TEST_F(ArcUtilTest, IsArcAvailable_Installed) {
auto* command_line = base::CommandLine::ForCurrentProcess();
// If ARC is not installed, IsArcAvailable() should return false,
// regardless of EnableARC feature.
command_line->InitFromArgv({""});
// Not available, by-default.
EXPECT_FALSE(IsArcAvailable());
EXPECT_FALSE(IsArcKioskAvailable());
{
ScopedArcFeature feature(true);
EXPECT_FALSE(IsArcAvailable());
EXPECT_FALSE(IsArcKioskAvailable());
}
{
ScopedArcFeature feature(false);
EXPECT_FALSE(IsArcAvailable());
EXPECT_FALSE(IsArcKioskAvailable());
}
// If ARC is installed, IsArcAvailable() should return true when EnableARC
// feature is set.
command_line->InitFromArgv({"", "--arc-available"});
// Not available, by-default, too.
EXPECT_FALSE(IsArcAvailable());
// ARC is available in kiosk mode if installed.
EXPECT_TRUE(IsArcKioskAvailable());
{
ScopedArcFeature feature(true);
EXPECT_TRUE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
}
{
ScopedArcFeature feature(false);
EXPECT_FALSE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
}
// If ARC is installed, IsArcAvailable() should return true when EnableARC
// feature is set.
command_line->InitFromArgv({"", "--arc-availability=installed"});
// Not available, by-default, too.
EXPECT_FALSE(IsArcAvailable());
// ARC is available in kiosk mode if installed.
EXPECT_TRUE(IsArcKioskAvailable());
{
ScopedArcFeature feature(true);
EXPECT_TRUE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
}
{
ScopedArcFeature feature(false);
EXPECT_FALSE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
}
}
TEST_F(ArcUtilTest, IsArcAvailable_OfficiallySupported) {
// Regardless of FeatureList, IsArcAvailable() should return true.
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--enable-arc"});
EXPECT_TRUE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
command_line->InitFromArgv({"", "--arc-availability=officially-supported"});
EXPECT_TRUE(IsArcAvailable());
EXPECT_TRUE(IsArcKioskAvailable());
}
TEST_F(ArcUtilTest, IsArcVmEnabled) {
EXPECT_FALSE(IsArcVmEnabled());
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--enable-arcvm"});
EXPECT_TRUE(IsArcVmEnabled());
}
TEST_F(ArcUtilTest, GetArcAndroidSdkVersionAsInt) {
// Make sure that the function does not crash even when /etc/lsb-release is
// not available (e.g. unit tests) or corrupted.
EXPECT_EQ(kMaxArcVersion, GetArcAndroidSdkVersionAsInt());
}
TEST_F(ArcUtilTest, IsArcVmRtVcpuEnabled) {
{
ScopedRtVcpuFeature feature(false, false);
EXPECT_FALSE(IsArcVmRtVcpuEnabled(2));
EXPECT_FALSE(IsArcVmRtVcpuEnabled(4));
EXPECT_FALSE(IsArcVmRtVcpuEnabled(8));
}
{
ScopedRtVcpuFeature feature(true, false);
EXPECT_TRUE(IsArcVmRtVcpuEnabled(2));
EXPECT_FALSE(IsArcVmRtVcpuEnabled(4));
EXPECT_FALSE(IsArcVmRtVcpuEnabled(8));
}
{
ScopedRtVcpuFeature feature(false, true);
EXPECT_FALSE(IsArcVmRtVcpuEnabled(2));
EXPECT_TRUE(IsArcVmRtVcpuEnabled(4));
EXPECT_TRUE(IsArcVmRtVcpuEnabled(8));
}
{
ScopedRtVcpuFeature feature(true, true);
EXPECT_TRUE(IsArcVmRtVcpuEnabled(2));
EXPECT_TRUE(IsArcVmRtVcpuEnabled(4));
EXPECT_TRUE(IsArcVmRtVcpuEnabled(8));
}
}
TEST_F(ArcUtilTest, IsArcVmUseHugePages) {
EXPECT_FALSE(IsArcVmUseHugePages());
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arcvm-use-hugepages"});
EXPECT_TRUE(IsArcVmUseHugePages());
}
TEST_F(ArcUtilTest, IsArcVmDevConfIgnored) {
EXPECT_FALSE(IsArcVmDevConfIgnored());
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--ignore-arcvm-dev-conf"});
EXPECT_TRUE(IsArcVmDevConfIgnored());
}
TEST_F(ArcUtilTest, GetArcVmUreadaheadMode) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({""});
EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
command_line->InitFromArgv({"", "--arc-disable-ureadahead"});
EXPECT_EQ(ArcVmUreadaheadMode::DISABLED, GetArcVmUreadaheadMode());
command_line->InitFromArgv(
{"", "--arc-disable-ureadahead", "--arcvm-ureadahead-mode=readahead"});
EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=readahead"});
EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=generate"});
EXPECT_EQ(ArcVmUreadaheadMode::GENERATE, GetArcVmUreadaheadMode());
command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=disabled"});
EXPECT_EQ(ArcVmUreadaheadMode::DISABLED, GetArcVmUreadaheadMode());
}
TEST_F(ArcUtilTest, UreadaheadDefault) {
EXPECT_FALSE(IsUreadaheadDisabled());
}
TEST_F(ArcUtilTest, UreadaheadDisabled) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arc-disable-ureadahead"});
EXPECT_TRUE(IsUreadaheadDisabled());
}
TEST_F(ArcUtilTest, HostUreadaheadGenerationDefault) {
EXPECT_FALSE(IsHostUreadaheadGeneration());
EXPECT_FALSE(IsUreadaheadDisabled());
}
TEST_F(ArcUtilTest, HostUreadaheadGenerationSet) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arc-host-ureadahead-generation"});
EXPECT_TRUE(IsHostUreadaheadGeneration());
EXPECT_FALSE(IsUreadaheadDisabled());
}
// TODO(hidehiko): Add test for IsArcKioskMode().
// It depends on UserManager, but a utility to inject fake instance is
// available only in chrome/. To use it in components/, refactoring is needed.
TEST_F(ArcUtilTest, IsArcOptInVerificationDisabled) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({""});
EXPECT_FALSE(IsArcOptInVerificationDisabled());
command_line->InitFromArgv({"", "--disable-arc-opt-in-verification"});
EXPECT_TRUE(IsArcOptInVerificationDisabled());
}
TEST_F(ArcUtilTest, IsArcAllowedForUser) {
user_manager::FakeUserManager* fake_user_manager =
new user_manager::FakeUserManager();
user_manager::ScopedUserManager scoped_user_manager(
base::WrapUnique(fake_user_manager));
TestingPrefServiceSimple local_state;
fake_user_manager->set_local_state(&local_state);
struct {
user_manager::UserType user_type;
bool expected_allowed;
} const kTestCases[] = {
{user_manager::USER_TYPE_REGULAR, true},
{user_manager::USER_TYPE_GUEST, false},
{user_manager::USER_TYPE_PUBLIC_ACCOUNT, true},
{user_manager::USER_TYPE_KIOSK_APP, false},
{user_manager::USER_TYPE_CHILD, true},
{user_manager::USER_TYPE_ARC_KIOSK_APP, true},
{user_manager::USER_TYPE_ACTIVE_DIRECTORY, true},
};
for (const auto& test_case : kTestCases) {
const FakeUser user(test_case.user_type);
EXPECT_EQ(test_case.expected_allowed, IsArcAllowedForUser(&user))
<< "User type=" << test_case.user_type;
}
// An ephemeral user is a logged in user but unknown to UserManager when
// ephemeral policy is set.
fake_user_manager->SetEphemeralUsersEnabled(true);
fake_user_manager->UserLoggedIn(
AccountId::FromUserEmailGaiaId("test@test.com", "9876543210"),
"test@test.com-hash", false /* browser_restart */, false /* is_child */);
const user_manager::User* ephemeral_user = fake_user_manager->GetActiveUser();
ASSERT_TRUE(ephemeral_user);
ASSERT_TRUE(fake_user_manager->IsUserCryptohomeDataEphemeral(
ephemeral_user->GetAccountId()));
// Ephemeral user is also allowed for ARC.
EXPECT_TRUE(IsArcAllowedForUser(ephemeral_user));
}
TEST_F(ArcUtilTest, ArcStartModeDefault) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arc-availability=installed"});
EXPECT_FALSE(ShouldArcAlwaysStart());
EXPECT_FALSE(ShouldArcAlwaysStartWithNoPlayStore());
}
TEST_F(ArcUtilTest, ArcStartModeWithoutPlayStore) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv(
{"", "--arc-availability=installed",
"--arc-start-mode=always-start-with-no-play-store"});
EXPECT_TRUE(ShouldArcAlwaysStart());
EXPECT_TRUE(ShouldArcAlwaysStartWithNoPlayStore());
}
// Verifies that ARC manual start is activated by switch.
TEST_F(ArcUtilTest, ArcStartModeManually) {
base::CommandLine::ForCurrentProcess()->InitFromArgv(
{"", "--arc-start-mode=manual"});
EXPECT_FALSE(ShouldArcAlwaysStart());
EXPECT_TRUE(ShouldArcStartManually());
}
// Verifies that ARC manual start is disabled by default.
TEST_F(ArcUtilTest, ArcStartModeManuallyDisabledByDefault) {
EXPECT_FALSE(ShouldArcAlwaysStart());
EXPECT_FALSE(ShouldArcStartManually());
}
TEST_F(ArcUtilTest, ScaleFactorToDensity) {
// Test all standard scale factors
EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(1.0f));
EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(1.25f));
EXPECT_EQ(213, GetLcdDensityForDeviceScaleFactor(1.6f));
EXPECT_EQ(240, GetLcdDensityForDeviceScaleFactor(display::kDsf_1_777));
EXPECT_EQ(240, GetLcdDensityForDeviceScaleFactor(display::kDsf_1_8));
EXPECT_EQ(240, GetLcdDensityForDeviceScaleFactor(2.0f));
EXPECT_EQ(280, GetLcdDensityForDeviceScaleFactor(display::kDsf_2_252));
EXPECT_EQ(280, GetLcdDensityForDeviceScaleFactor(2.4f));
EXPECT_EQ(320, GetLcdDensityForDeviceScaleFactor(display::kDsf_2_666));
// Bad scale factors shouldn't blow up.
EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(0.5f));
EXPECT_EQ(160, GetLcdDensityForDeviceScaleFactor(-0.1f));
EXPECT_EQ(180, GetLcdDensityForDeviceScaleFactor(1.5f));
EXPECT_EQ(1200, GetLcdDensityForDeviceScaleFactor(10.f));
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv({"", "--arc-scale=280"});
EXPECT_EQ(280, GetLcdDensityForDeviceScaleFactor(1.234f));
command_line->InitFromArgv({"", "--arc-scale=120"});
EXPECT_EQ(120, GetLcdDensityForDeviceScaleFactor(1.234f));
command_line->InitFromArgv({"", "--arc-scale=abc"});
EXPECT_EQ(240, GetLcdDensityForDeviceScaleFactor(2.0));
}
TEST_F(ArcUtilTest, ConfigureUpstartJobs_Success) {
std::deque<JobDesc> jobs{
JobDesc{"Job_2dA", UpstartOperation::JOB_STOP, {}},
JobDesc{"Job_2dB", UpstartOperation::JOB_STOP_AND_START, {}},
JobDesc{"Job_2dC", UpstartOperation::JOB_START, {}},
};
bool result = false;
StartRecordingUpstartOperations();
ConfigureUpstartJobs(
jobs,
base::BindLambdaForTesting(
[&result, quit_closure = task_environment()->QuitClosure()](bool r) {
result = r;
quit_closure.Run();
}));
task_environment()->RunUntilQuit();
EXPECT_TRUE(result);
auto ops = upstart_operations();
ASSERT_EQ(4u, ops.size());
EXPECT_EQ(ops[0].first, "Job_2dA");
EXPECT_FALSE(ops[0].second);
EXPECT_EQ(ops[1].first, "Job_2dB");
EXPECT_FALSE(ops[1].second);
EXPECT_EQ(ops[2].first, "Job_2dB");
EXPECT_TRUE(ops[2].second);
EXPECT_EQ(ops[3].first, "Job_2dC");
EXPECT_TRUE(ops[3].second);
}
TEST_F(ArcUtilTest, ConfigureUpstartJobs_StopFail) {
std::deque<JobDesc> jobs{
JobDesc{"Job_2dA", UpstartOperation::JOB_STOP, {}},
JobDesc{"Job_2dB", UpstartOperation::JOB_STOP_AND_START, {}},
JobDesc{"Job_2dC", UpstartOperation::JOB_START, {}},
};
// Confirm that failing to stop a job is ignored.
bool result = false;
InjectUpstartStopJobFailure("Job_2dA");
ConfigureUpstartJobs(
jobs,
base::BindLambdaForTesting(
[&result, quit_closure = task_environment()->QuitClosure()](bool r) {
result = r;
quit_closure.Run();
}));
task_environment()->RunUntilQuit();
EXPECT_TRUE(result);
// Do the same for the second task.
result = false;
InjectUpstartStopJobFailure("Job_2dB");
ConfigureUpstartJobs(
jobs,
base::BindLambdaForTesting(
[&result, quit_closure = task_environment()->QuitClosure()](bool r) {
result = r;
quit_closure.Run();
}));
task_environment()->RunUntilQuit();
EXPECT_TRUE(result);
}
TEST_F(ArcUtilTest, ConfigureUpstartJobs_StartFail) {
std::deque<JobDesc> jobs{
JobDesc{"Job_2dA", UpstartOperation::JOB_STOP, {}},
JobDesc{"Job_2dB", UpstartOperation::JOB_STOP_AND_START, {}},
JobDesc{"Job_2dC", UpstartOperation::JOB_START, {}},
};
// Confirm that failing to start a job is not ignored.
bool result = true;
InjectUpstartStartJobFailure("Job_2dB");
ConfigureUpstartJobs(
jobs,
base::BindLambdaForTesting(
[&result, quit_closure = task_environment()->QuitClosure()](bool r) {
result = r;
quit_closure.Run();
}));
task_environment()->RunUntilQuit();
EXPECT_FALSE(result);
// Do the same for the third task.
result = true;
InjectUpstartStartJobFailure("Job_2dC");
ConfigureUpstartJobs(
std::move(jobs),
base::BindLambdaForTesting(
[&result, quit_closure = task_environment()->QuitClosure()](bool r) {
result = r;
quit_closure.Run();
}));
task_environment()->RunUntilQuit();
EXPECT_FALSE(result);
}
TEST_F(ArcUtilTest, GetArcWindowTaskId) {
std::unique_ptr<aura::Window> window(
aura::test::CreateTestWindowWithId(100, nullptr));
exo::SetShellApplicationId(window.get(), "org.chromium.arc.100");
{
auto task_id = GetWindowTaskId(window.get());
EXPECT_TRUE(task_id.has_value());
EXPECT_EQ(task_id.value(), 100);
}
{
auto session_id = GetWindowSessionId(window.get());
EXPECT_FALSE(session_id.has_value());
}
{
auto task_or_session_id = GetWindowTaskOrSessionId(window.get());
EXPECT_TRUE(task_or_session_id.has_value());
EXPECT_EQ(task_or_session_id.value(), 100);
}
}
TEST_F(ArcUtilTest, GetArcWindowSessionId) {
std::unique_ptr<aura::Window> window(
aura::test::CreateTestWindowWithId(200, nullptr));
exo::SetShellApplicationId(window.get(), "org.chromium.arc.session.200");
{
auto task_id = GetWindowTaskId(window.get());
EXPECT_FALSE(task_id.has_value());
}
{
auto session_id = GetWindowSessionId(window.get());
EXPECT_TRUE(session_id.has_value());
EXPECT_EQ(session_id.value(), 200);
}
{
auto task_or_session_id = GetWindowTaskOrSessionId(window.get());
EXPECT_TRUE(task_or_session_id.has_value());
EXPECT_EQ(task_or_session_id.value(), 200);
}
}
TEST_F(ArcUtilTest, SetAndGetArcVmDataMigrationStatus) {
constexpr ArcVmDataMigrationStatus statuses[] = {
ArcVmDataMigrationStatus::kFinished,
ArcVmDataMigrationStatus::kStarted,
ArcVmDataMigrationStatus::kConfirmed,
ArcVmDataMigrationStatus::kNotified,
ArcVmDataMigrationStatus::kUnnotified,
};
for (const auto status : statuses) {
SetArcVmDataMigrationStatus(profile_prefs(), status);
EXPECT_EQ(status, GetArcVmDataMigrationStatus(profile_prefs()));
}
}
// Tests that ShouldUseVirtioBlkData() returns true when virtio-blk /data is
// enabled via the kEnableVirtioBlkForData feature.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_VirtioBlkForDataFeatureEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableVirtioBlkForData);
EXPECT_FALSE(base::FeatureList::IsEnabled(kEnableArcVmDataMigration));
EXPECT_TRUE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that ShouldUseVirtioBlkData() returns false when ARCVM /data is enabled
// but the user has not been notified yet.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_ArcVmDataMigration_Unnotified) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableArcVmDataMigration);
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kUnnotified);
EXPECT_FALSE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that ShouldUseVirtioBlkData() returns false when ARCVM /data is enabled
// but the user has just been notified of its availability.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_ArcVmDataMigration_Notified) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableArcVmDataMigration);
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kNotified);
EXPECT_FALSE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that ShouldUseVirtioBlkData() returns false when ARCVM /data is enabled
// but the user has just confirmed the migration.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_ArcVmDataMigration_Confirmed) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableArcVmDataMigration);
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kConfirmed);
EXPECT_FALSE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that ShouldUseVirtioBlkData() returns false when ARCVM /data is enabled
// and the migration has started, but not finished yet.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_ArcVmDataMigration_Started) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableArcVmDataMigration);
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kStarted);
EXPECT_FALSE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that ShouldUseVirtioBlkData() returns true when ARCVM /data is enabled
// and the migration has finished.
TEST_F(ArcUtilTest, ShouldUseVirtioBlkData_ArcVmDataMigration_Finished) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kEnableArcVmDataMigration);
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kFinished);
EXPECT_TRUE(ShouldUseVirtioBlkData(profile_prefs()));
}
// Tests that GetDaysUntilArcVmDataMigrationDeadline() returns the correct value
// when it is called just after the ARCVM /data migration notification is shown
// for the first time.
TEST_F(ArcUtilTest,
GetDaysUntilArcVmDataMigrationDeadline_JustAfterFirstNotification) {
profile_prefs()->SetTime(prefs::kArcVmDataMigrationNotificationFirstShownTime,
base::Time::Now());
const int days_until_deadline =
GetDaysUntilArcVmDataMigrationDeadline(profile_prefs());
// Take into account cases where the test is executed around midnight.
EXPECT_TRUE(
days_until_deadline == kArcVmDataMigrationNumberOfDismissibleDays ||
days_until_deadline == (kArcVmDataMigrationNumberOfDismissibleDays - 1))
<< "days_until_deadline = " << days_until_deadline;
}
// Tests that GetDaysUntilArcVmDataMigrationDeadline() returns the correct value
// when it is called after kArcVmDataMigrationDismissibleTimeDelta has passed.
TEST_F(ArcUtilTest, GetDaysUntilArcVmDataMigrationDeadline_JustAfterDeadline) {
// Remaining days should be 1 (i.e., the migration should be done today).
profile_prefs()->SetTime(
prefs::kArcVmDataMigrationNotificationFirstShownTime,
base::Time::Now() - kArcVmDataMigrationDismissibleTimeDelta);
EXPECT_EQ(GetDaysUntilArcVmDataMigrationDeadline(profile_prefs()), 1);
}
// Tests that GetDaysUntilArcVmDataMigrationDeadline() returns the correct value
// when it is called after more days than kArcVmDataMigrationDismissibleDays
// have passed.
TEST_F(ArcUtilTest, GetDaysUntilArcVmDataMigrationDeadline_Overdue) {
// Remaining days should be kept 1.
profile_prefs()->SetTime(
prefs::kArcVmDataMigrationNotificationFirstShownTime,
base::Time::Now() -
(kArcVmDataMigrationDismissibleTimeDelta + base::Days(10)));
EXPECT_EQ(GetDaysUntilArcVmDataMigrationDeadline(profile_prefs()), 1);
}
// Tests that GetDaysUntilArcVmDataMigrationDeadline() returns the correct value
// when the migration is in progress.
TEST_F(ArcUtilTest, GetDaysUntilArcVmDataMigrationDeadline_MigrationStarted) {
SetArcVmDataMigrationStatus(profile_prefs(),
ArcVmDataMigrationStatus::kStarted);
profile_prefs()->SetTime(prefs::kArcVmDataMigrationNotificationFirstShownTime,
base::Time::Now());
EXPECT_EQ(GetDaysUntilArcVmDataMigrationDeadline(profile_prefs()), 1);
}
TEST_F(ArcUtilTest, GetDesiredDiskImageSizeForArcVmDataMigrationInBytes) {
EXPECT_EQ(GetDesiredDiskImageSizeForArcVmDataMigrationInBytes(0, 0),
4ULL << 30 /* kMinimumDiskImageSizeInBytes = 4 GB */);
EXPECT_EQ(GetDesiredDiskImageSizeForArcVmDataMigrationInBytes(
4ULL << 30 /* android_data_size_in_bytes = 4 GB */,
32ULL << 30 /* free_disk_space_in_bytes = 32 GB */),
35782443008ULL /* ~33 GB */);
EXPECT_EQ(GetDesiredDiskImageSizeForArcVmDataMigrationInBytes(
32ULL << 30 /* android_data_size_in_bytes = 32 GB */,
4ULL << 30 /* free_disk_space_in_bytes = 4 GB */),
41795399680ULL /* ~39 GB */);
}
TEST_F(ArcUtilTest, GetRequiredFreeDiskSpaceForArcVmDataMigrationInBytes) {
EXPECT_EQ(GetRequiredFreeDiskSpaceForArcVmDataMigrationInBytes(0, 0),
1ULL << 30 /* kMinimumRequiredFreeDiskSpaceInBytes = 1 GB */);
EXPECT_EQ(GetRequiredFreeDiskSpaceForArcVmDataMigrationInBytes(
4ULL << 30 /* android_data_size_in_bytes = 4 GB */,
32ULL << 30 /* free_disk_space_in_bytes = 32 GB */),
3ULL * (512ULL << 20) /* 1.5 GB */);
EXPECT_EQ(GetRequiredFreeDiskSpaceForArcVmDataMigrationInBytes(
32ULL << 30 /* android_data_size_in_bytes = 32 GB */,
4ULL << 30 /* free_disk_space_in_bytes = 4 GB */),
4ULL << 30 /* 4 GB */);
}
} // namespace
} // namespace arc