blob: ddc53822c0ac247fc1c0ceabd40593df2ddb8496 [file] [log] [blame]
// Copyright 2017 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/installer/setup/user_experiment.h"
#include "base/macros.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "chrome/common/chrome_version.h"
#include "chrome/install_static/install_details.h"
#include "chrome/install_static/install_modes.h"
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/test/scoped_install_details.h"
#include "chrome/installer/util/experiment_metrics.h"
#include "chrome/installer/util/experiment_storage.h"
#include "chrome/installer/util/google_update_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace installer {
class UserExperimentTest : public ::testing::TestWithParam<bool> {
protected:
UserExperimentTest()
: system_level_(GetParam()),
root_(system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER),
install_details_(system_level_) {}
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(registry_override_manager_.OverrideRegistry(root_));
// Create the ClientState key.
base::win::RegKey key;
ASSERT_EQ(key.Create(root_, install_static::GetClientStateKeyPath().c_str(),
KEY_WOW64_64KEY | KEY_SET_VALUE),
ERROR_SUCCESS);
}
void SetProductVersion(const base::char16* version) {
SetClientsValue(google_update::kRegVersionField, version);
}
void SetOldProductVersion(const base::char16* version) {
SetClientsValue(google_update::kRegOldVersionField, version);
}
private:
void SetClientsValue(const base::char16* value_name,
const base::char16* value_data) {
base::win::RegKey key(
root_,
install_static::GetClientsKeyPath(install_static::GetAppGuid()).c_str(),
KEY_WOW64_64KEY | KEY_SET_VALUE);
ASSERT_TRUE(key.Valid());
ASSERT_EQ(key.WriteValue(value_name, value_data), ERROR_SUCCESS);
}
const bool system_level_;
const HKEY root_;
registry_util::RegistryOverrideManager registry_override_manager_;
install_static::ScopedInstallDetails install_details_;
DISALLOW_COPY_AND_ASSIGN(UserExperimentTest);
};
TEST_P(UserExperimentTest, WriteInitialStateNoData) {
ExperimentStorage storage;
// A first call should write the desired state.
WriteInitialState(&storage, ExperimentMetrics::kWaitingForUserLogon);
ExperimentMetrics metrics = ExperimentMetrics();
EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics));
EXPECT_EQ(metrics.state, ExperimentMetrics::kWaitingForUserLogon);
// A subsequent should update it state.
WriteInitialState(&storage, ExperimentMetrics::kSingletonWaitTimeout);
metrics = ExperimentMetrics();
EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics));
EXPECT_EQ(metrics.state, ExperimentMetrics::kSingletonWaitTimeout);
}
// Nothing should be written if the experiment is underway.
TEST_P(UserExperimentTest, WriteInitialStateInExperiment) {
ExperimentStorage storage;
{
ExperimentMetrics metrics = ExperimentMetrics();
metrics.state = ExperimentMetrics::kGroupAssigned;
storage.AcquireLock()->StoreMetrics(metrics);
}
WriteInitialState(&storage, ExperimentMetrics::kSingletonWaitTimeout);
ExperimentMetrics metrics = ExperimentMetrics();
EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics));
EXPECT_EQ(metrics.state, ExperimentMetrics::kGroupAssigned);
}
TEST_P(UserExperimentTest, IsDomainJoined) {
// Just make sure it doesn't crash or leak.
IsDomainJoined();
}
TEST_P(UserExperimentTest, IsSelectedForStudyFirstCall) {
ExperimentStorage storage;
auto lock = storage.AcquireLock();
// The first call will pick a study.
bool is_selected =
IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne);
// A value must have been written.
ExperimentStorage::Study participation = ExperimentStorage::kNoStudySelected;
ASSERT_TRUE(lock->ReadParticipation(&participation));
EXPECT_GE(participation, ExperimentStorage::kStudyOne);
EXPECT_LE(participation, ExperimentStorage::kStudyTwo);
// is_selected should be set based on the value that was written.
if (participation == ExperimentStorage::kStudyOne)
EXPECT_TRUE(is_selected);
else
EXPECT_FALSE(is_selected);
}
// A user selected into study one participates in both studies.
TEST_P(UserExperimentTest, IsSelectedForStudyOne) {
ExperimentStorage storage;
auto lock = storage.AcquireLock();
ASSERT_TRUE(lock->WriteParticipation(ExperimentStorage::kStudyOne));
EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne));
EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyTwo));
}
// A user selected into study two only participates in that study.
TEST_P(UserExperimentTest, IsSelectedForStudyTwo) {
ExperimentStorage storage;
auto lock = storage.AcquireLock();
ASSERT_TRUE(lock->WriteParticipation(ExperimentStorage::kStudyTwo));
EXPECT_FALSE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne));
EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyTwo));
}
// Ensure that group selection is within bounds.
TEST_P(UserExperimentTest, PickGroupStudyOne) {
int group = PickGroup(ExperimentStorage::kStudyOne);
EXPECT_GE(group, 0);
EXPECT_LT(group, ExperimentMetrics::kNumGroups);
}
// Ensure that group selection is within bounds.
TEST_P(UserExperimentTest, PickGroupStudyTwo) {
int group = PickGroup(ExperimentStorage::kStudyTwo);
EXPECT_GE(group, 0);
EXPECT_LT(group, ExperimentMetrics::kNumGroups);
}
// When there's nothing in the registry, default to false.
TEST_P(UserExperimentTest, IsUpdateRenamePendingNoRegistration) {
EXPECT_FALSE(IsUpdateRenamePending());
}
// No update is pending if "pv" matches the current version.
TEST_P(UserExperimentTest, IsUpdateRenamePendingNo) {
ASSERT_NO_FATAL_FAILURE(SetProductVersion(TEXT(CHROME_VERSION_STRING)));
EXPECT_FALSE(IsUpdateRenamePending());
}
// An update is pending if an old version needs to be restarted to be the
// current.
TEST_P(UserExperimentTest, IsUpdateRenamePendingYes) {
static constexpr base::char16 kSillyOldVersion[] = L"47.0.1.0";
ASSERT_STRNE(kSillyOldVersion, TEXT(CHROME_VERSION_STRING));
ASSERT_NO_FATAL_FAILURE(SetProductVersion(TEXT(CHROME_VERSION_STRING)));
ASSERT_NO_FATAL_FAILURE(SetOldProductVersion(kSillyOldVersion));
EXPECT_TRUE(IsUpdateRenamePending());
}
INSTANTIATE_TEST_SUITE_P(UserLevel,
UserExperimentTest,
::testing::Values(false));
INSTANTIATE_TEST_SUITE_P(SystemLevel,
UserExperimentTest,
::testing::Values(true));
} // namespace installer