Create client-configured field trial for using new seed file.
Create a client-configured field trial, SeedFileTrial, with two possible groups, a treatment group that will use the seed files group and a control group which will continue with status quo behavior. This CL also does the following: * Involved considering multiple different options for where to have the field trial setup take place with the following options considered: - In the SeedReaderWriter, rejected because, since both the safe seed store and the latest seed store have a corresponding SeedReaderWriter, we would be doing the setup twice. - In the VariationService, rejected because, by wanting to consolidate logic, it did not feel as correct of a spot as the seed store. * Removes plumbing channel to the SeedReaderWriter as well as the logic related to the channel in SeedReaderWriter. This is because behavior will now be determined by the field trial group instead of the release channel of a client. * Renames kDefaultGroup to kTestDefaultGroup in unittest to avoid naming collision Bug: 371181951 Change-Id: Ia870df79d4e00bd0fe272441a196e0ee75064c0e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5907254 Reviewed-by: Caitlin Fischer <caitlinfischer@google.com> Reviewed-by: Nate Fischer <ntfschr@chromium.org> Commit-Queue: Cristian Lopez <cristiandlopez@google.com> Cr-Commit-Position: refs/heads/main@{#1379240}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b48e78efbf
commit
fe35bf7c24
android_webview/browser
components/variations
cros_evaluate_seed
seed_reader_writer.ccseed_reader_writer.hseed_reader_writer_unittest.ccservice
variations_safe_seed_store_local_state.ccvariations_safe_seed_store_local_state.hvariations_seed_processor_unittest.ccvariations_seed_store.ccvariations_seed_store.hvariations_seed_store_unittest.ccvariations_test_utils.ccvariations_test_utils.hcontent/shell/browser
headless/lib/browser
@ -241,9 +241,9 @@ void AwFeatureListCreator::SetUpFieldTrials() {
|
||||
local_state_.get(), /*initial_seed=*/std::move(seed),
|
||||
/*signature_verification_enabled=*/g_signature_verification_enabled,
|
||||
std::make_unique<variations::VariationsSafeSeedStoreLocalState>(
|
||||
local_state_.get(), client_->GetChannelForVariations(),
|
||||
client_->GetVariationsSeedFileDir()),
|
||||
local_state_.get(), client_->GetVariationsSeedFileDir()),
|
||||
client_->GetChannelForVariations(), client_->GetVariationsSeedFileDir(),
|
||||
/*entropy_providers=*/nullptr,
|
||||
/*use_first_run_prefs=*/false);
|
||||
|
||||
if (!seed_date.is_null())
|
||||
|
@ -259,8 +259,7 @@ std::unique_ptr<CrOSVariationsFieldTrialCreator> GetFieldTrialCreator(
|
||||
safe_seed = std::make_unique<EarlyBootSafeSeed>(safe_seed_details.value());
|
||||
} else {
|
||||
safe_seed = std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state, client->GetChannelForVariations(),
|
||||
client->GetVariationsSeedFileDir());
|
||||
local_state, client->GetVariationsSeedFileDir());
|
||||
}
|
||||
auto seed_store = std::make_unique<VariationsSeedStore>(
|
||||
local_state, /*initial_seed=*/nullptr,
|
||||
|
@ -241,8 +241,7 @@ CreateTestCrOSVariationsFieldTrialCreator(
|
||||
(void)safe_seed_details;
|
||||
|
||||
auto safe_seed = std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state, client->GetChannelForVariations(),
|
||||
client->GetVariationsSeedFileDir());
|
||||
local_state, client->GetVariationsSeedFileDir());
|
||||
auto seed_store = std::make_unique<VariationsSeedStore>(
|
||||
local_state, /*initial_seed=*/nullptr,
|
||||
/*signature_verification_enabled=*/true, std::move(safe_seed),
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/metrics/field_trial.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
@ -23,11 +24,11 @@ namespace {
|
||||
// information.
|
||||
constexpr char kSeedWriterHistogramSuffix[] = "VariationsSeedsV1";
|
||||
|
||||
// Returns true if a seed should be written to its new storage.
|
||||
bool ShouldWriteToNewSeedStorage(version_info::Channel channel) {
|
||||
return channel == version_info::Channel::CANARY ||
|
||||
channel == version_info::Channel::DEV ||
|
||||
channel == version_info::Channel::BETA;
|
||||
// Returns true if a seed should be written to a seed file.
|
||||
bool ShouldWriteToSeedFile() {
|
||||
// Use the plain FieldTrialList API here because the trial is registered
|
||||
// client-side in VariationsSeedStore SetUpSeedFileTrial().
|
||||
return base::FieldTrialList::FindFullName(kSeedFileTrial) == kSeedFilesGroup;
|
||||
}
|
||||
|
||||
// Serializes and returns seed data used during write to disk. Will be run
|
||||
@ -52,11 +53,9 @@ SeedReaderWriter::SeedReaderWriter(
|
||||
PrefService* local_state,
|
||||
const base::FilePath& seed_file_dir,
|
||||
base::FilePath::StringPieceType seed_filename,
|
||||
const version_info::Channel channel,
|
||||
std::string_view seed_pref,
|
||||
scoped_refptr<base::SequencedTaskRunner> file_task_runner)
|
||||
: local_state_(local_state),
|
||||
channel_(channel),
|
||||
seed_pref_(seed_pref),
|
||||
file_task_runner_(std::move(file_task_runner)) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
@ -79,7 +78,7 @@ void SeedReaderWriter::StoreValidatedSeed(
|
||||
const std::string& base64_seed_data) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
local_state_->SetString(seed_pref_, base64_seed_data);
|
||||
if (ShouldWriteToNewSeedStorage(channel_)) {
|
||||
if (ShouldWriteToSeedFile()) {
|
||||
ScheduleSeedFileWrite(compressed_seed_data);
|
||||
}
|
||||
}
|
||||
@ -87,17 +86,18 @@ void SeedReaderWriter::StoreValidatedSeed(
|
||||
void SeedReaderWriter::ClearSeed() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
local_state_->ClearPref(seed_pref_);
|
||||
// TODO(crbug.com/372009105): Remove if-statement when all channels are ready
|
||||
// to launch.
|
||||
if (!ShouldWriteToNewSeedStorage(channel_) && seed_writer_ &&
|
||||
!base::PathExists(seed_writer_->path())) {
|
||||
// TODO(crbug.com/372009105): Remove if-statements when experiment has ended.
|
||||
if (!seed_writer_) {
|
||||
return;
|
||||
}
|
||||
// Although only pre-Stable clients write seeds to dedicated seed files,
|
||||
// attempt to clear the seed file on all channels here. If a client
|
||||
// switches from a pre-Stable client to a Stable client, their device
|
||||
// could have a seed file.
|
||||
ScheduleSeedFileWrite(std::string());
|
||||
|
||||
// Although only clients in the treatment group write seeds to dedicated seed
|
||||
// files, attempt to clear the seed file for all groups here. If a client
|
||||
// switches experiment groups or channels, their device could have a seed file
|
||||
// with stale seed data.
|
||||
if (ShouldWriteToSeedFile() || base::PathExists(seed_writer_->path())) {
|
||||
ScheduleSeedFileWrite(std::string());
|
||||
}
|
||||
}
|
||||
|
||||
void SeedReaderWriter::SetTimerForTesting(base::OneShotTimer* timer_override) {
|
||||
|
@ -17,12 +17,17 @@
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/version_info/channel.h"
|
||||
|
||||
class PrefService;
|
||||
|
||||
namespace variations {
|
||||
|
||||
// Trial and group names for the seed file experiment.
|
||||
const char kSeedFileTrial[] = "SeedFileTrial";
|
||||
const char kDefaultGroup[] = "Default";
|
||||
const char kControlGroup[] = "Control_V1";
|
||||
const char kSeedFilesGroup[] = "SeedFiles_V1";
|
||||
|
||||
// Handles reading and writing seeds to disk.
|
||||
class COMPONENT_EXPORT(VARIATIONS) SeedReaderWriter
|
||||
: public base::ImportantFileWriter::BackgroundDataSerializer {
|
||||
@ -32,16 +37,13 @@ class COMPONENT_EXPORT(VARIATIONS) SeedReaderWriter
|
||||
// Android Webview intentionally uses an empty path as it uses only local
|
||||
// state to store seeds.
|
||||
// `seed_filename` is the base name of a file in which seed data is stored.
|
||||
// `channel` describes the browser's release channel.
|
||||
// `seed_pref` is a variations pref (kVariationsCompressedSeed or
|
||||
// kVariationsSafeCompressed) denoting the type of seed handled by this
|
||||
// SeedReaderWriter.
|
||||
// `file_task_runner` handles IO-related tasks. Must not be
|
||||
// null.
|
||||
// `file_task_runner` handles IO-related tasks. Must not be null.
|
||||
SeedReaderWriter(PrefService* local_state,
|
||||
const base::FilePath& seed_file_dir,
|
||||
base::FilePath::StringPieceType seed_filename,
|
||||
const version_info::Channel channel,
|
||||
std::string_view seed_pref,
|
||||
scoped_refptr<base::SequencedTaskRunner> file_task_runner =
|
||||
base::ThreadPool::CreateSequencedTaskRunner(
|
||||
@ -77,9 +79,6 @@ class COMPONENT_EXPORT(VARIATIONS) SeedReaderWriter
|
||||
// Pref service used to persist seeds.
|
||||
raw_ptr<PrefService> local_state_;
|
||||
|
||||
// Channel the client is apart of.
|
||||
const version_info::Channel channel_;
|
||||
|
||||
// A variations pref (kVariationsCompressedSeed or kVariationsSafeCompressed)
|
||||
// denoting the type of seed handled by this SeedReaderWriter.
|
||||
std::string_view seed_pref_;
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "base/base64.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/test/mock_entropy_provider.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/timer/mock_timer.h"
|
||||
@ -44,30 +46,33 @@ std::string CreateCompressedVariationsSeed() {
|
||||
}
|
||||
|
||||
struct SeedReaderWriterTestParams {
|
||||
using TupleT = std::tuple<std::string_view, version_info::Channel>;
|
||||
using TupleT = std::tuple<std::string_view, std::string_view>;
|
||||
|
||||
SeedReaderWriterTestParams(std::string_view seed_pref,
|
||||
version_info::Channel channel)
|
||||
: seed_pref(seed_pref), channel(channel) {}
|
||||
std::string_view field_trial_group)
|
||||
: seed_pref(seed_pref), field_trial_group(field_trial_group) {}
|
||||
|
||||
explicit SeedReaderWriterTestParams(const TupleT& t)
|
||||
: SeedReaderWriterTestParams(std::get<0>(t), std::get<1>(t)) {}
|
||||
|
||||
std::string_view seed_pref;
|
||||
const version_info::Channel channel;
|
||||
std::string_view field_trial_group;
|
||||
};
|
||||
|
||||
class SeedReaderWriterTest : public TestWithParam<SeedReaderWriterTestParams> {
|
||||
public:
|
||||
SeedReaderWriterTest() : file_writer_thread_("SeedReaderWriter Test thread") {
|
||||
scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
|
||||
file_writer_thread_.Start();
|
||||
CHECK(temp_dir_.CreateUniqueTempDir());
|
||||
SetUpSeedFileTrial(std::string(GetParam().field_trial_group));
|
||||
temp_seed_file_path_ = temp_dir_.GetPath().Append(kSeedFilename);
|
||||
VariationsSeedStore::RegisterPrefs(local_state_.registry());
|
||||
}
|
||||
~SeedReaderWriterTest() override = default;
|
||||
|
||||
protected:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
base::FilePath temp_seed_file_path_;
|
||||
base::Thread file_writer_thread_;
|
||||
base::ScopedTempDir temp_dir_;
|
||||
@ -75,17 +80,20 @@ class SeedReaderWriterTest : public TestWithParam<SeedReaderWriterTestParams> {
|
||||
base::MockOneShotTimer timer_;
|
||||
};
|
||||
|
||||
class SeedReaderWriterPreStableTest : public SeedReaderWriterTest {};
|
||||
class SeedReaderWriterSeedFilesGroupTest : public SeedReaderWriterTest {};
|
||||
class SeedReaderWriterControlAndLocalStateOnlyGroupTest
|
||||
: public SeedReaderWriterTest {};
|
||||
class SeedReaderWriterAllGroupsTest : public SeedReaderWriterTest {};
|
||||
|
||||
class SeedReaderWriterStableAndUnknownTest : public SeedReaderWriterTest {};
|
||||
|
||||
// Verifies pre-stable clients write seeds to Local State and the seed file.
|
||||
TEST_P(SeedReaderWriterPreStableTest, WriteSeed) {
|
||||
// Verifies clients in SeedFiles group write seeds to Local State and the
|
||||
// seed file.
|
||||
TEST_P(SeedReaderWriterSeedFilesGroupTest, WriteSeed) {
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
// Initialize seed_reader_writer with test thread and timer.
|
||||
SeedReaderWriter seed_reader_writer(
|
||||
&local_state_, /*seed_file_dir=*/temp_dir_.GetPath(), kSeedFilename,
|
||||
GetParam().channel, GetParam().seed_pref,
|
||||
file_writer_thread_.task_runner());
|
||||
GetParam().seed_pref, file_writer_thread_.task_runner());
|
||||
seed_reader_writer.SetTimerForTesting(&timer_);
|
||||
|
||||
// Create and store seed.
|
||||
@ -109,22 +117,22 @@ TEST_P(SeedReaderWriterPreStableTest, WriteSeed) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
SeedReaderWriterPreStableTest,
|
||||
SeedReaderWriterSeedFilesGroupTest,
|
||||
::testing::ConvertGenerator<SeedReaderWriterTestParams::TupleT>(
|
||||
::testing::Combine(
|
||||
::testing::Values(prefs::kVariationsCompressedSeed,
|
||||
prefs::kVariationsSafeCompressedSeed),
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA))));
|
||||
::testing::Values(kSeedFilesGroup))));
|
||||
|
||||
// Verifies stable and unknown channel clients write seeds only to Local State.
|
||||
TEST_P(SeedReaderWriterStableAndUnknownTest, WriteSeed) {
|
||||
// Verifies clients in the control group and those using local state only write
|
||||
// seeds only to Local State.
|
||||
TEST_P(SeedReaderWriterControlAndLocalStateOnlyGroupTest, WriteSeed) {
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
// Initialize seed_reader_writer with test thread and timer.
|
||||
SeedReaderWriter seed_reader_writer(
|
||||
&local_state_, /*seed_file_dir=*/temp_dir_.GetPath(), kSeedFilename,
|
||||
GetParam().channel, GetParam().seed_pref,
|
||||
file_writer_thread_.task_runner());
|
||||
GetParam().seed_pref, file_writer_thread_.task_runner());
|
||||
seed_reader_writer.SetTimerForTesting(&timer_);
|
||||
|
||||
// Create and store seed.
|
||||
@ -145,23 +153,24 @@ TEST_P(SeedReaderWriterStableAndUnknownTest, WriteSeed) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
SeedReaderWriterStableAndUnknownTest,
|
||||
SeedReaderWriterControlAndLocalStateOnlyGroupTest,
|
||||
::testing::ConvertGenerator<SeedReaderWriterTestParams::TupleT>(
|
||||
::testing::Combine(
|
||||
::testing::Values(prefs::kVariationsCompressedSeed,
|
||||
prefs::kVariationsSafeCompressedSeed),
|
||||
::testing::Values(version_info::Channel::STABLE,
|
||||
version_info::Channel::UNKNOWN))));
|
||||
::testing::Values(kControlGroup, std::string()))));
|
||||
|
||||
// Verifies that writing seeds with an empty path for `seed_file_dir` does not
|
||||
// cause a crash.
|
||||
TEST_P(SeedReaderWriterTest, EmptySeedFilePathIsValid) {
|
||||
TEST_P(SeedReaderWriterAllGroupsTest, EmptySeedFilePathIsValid) {
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
// Initialize seed_reader_writer with test thread and timer and an empty file
|
||||
// path.
|
||||
SeedReaderWriter seed_reader_writer(
|
||||
&local_state_,
|
||||
/*seed_file_dir=*/base::FilePath(), kSeedFilename, GetParam().channel,
|
||||
GetParam().seed_pref, file_writer_thread_.task_runner());
|
||||
SeedReaderWriter seed_reader_writer(&local_state_,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
kSeedFilename, GetParam().seed_pref,
|
||||
file_writer_thread_.task_runner());
|
||||
seed_reader_writer.SetTimerForTesting(&timer_);
|
||||
|
||||
// Create and store seed.
|
||||
@ -180,12 +189,13 @@ TEST_P(SeedReaderWriterTest, EmptySeedFilePathIsValid) {
|
||||
}
|
||||
|
||||
// Verifies that a seed is cleared from both Local State and the seed file.
|
||||
TEST_P(SeedReaderWriterTest, ClearSeed) {
|
||||
TEST_P(SeedReaderWriterAllGroupsTest, ClearSeed) {
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
// Initialize seed_reader_writer with test thread and timer.
|
||||
SeedReaderWriter seed_reader_writer(
|
||||
&local_state_, /*seed_file_dir=*/temp_dir_.GetPath(), kSeedFilename,
|
||||
GetParam().channel, GetParam().seed_pref,
|
||||
file_writer_thread_.task_runner());
|
||||
GetParam().seed_pref, file_writer_thread_.task_runner());
|
||||
seed_reader_writer.SetTimerForTesting(&timer_);
|
||||
|
||||
// Create and store seed.
|
||||
@ -205,17 +215,14 @@ TEST_P(SeedReaderWriterTest, ClearSeed) {
|
||||
EXPECT_THAT(seed_file_data, IsEmpty());
|
||||
EXPECT_THAT(local_state_.GetString(GetParam().seed_pref), IsEmpty());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
SeedReaderWriterTest,
|
||||
SeedReaderWriterAllGroupsTest,
|
||||
::testing::ConvertGenerator<SeedReaderWriterTestParams::TupleT>(
|
||||
::testing::Combine(
|
||||
::testing::Values(prefs::kVariationsCompressedSeed,
|
||||
prefs::kVariationsSafeCompressedSeed),
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA,
|
||||
version_info::Channel::STABLE,
|
||||
version_info::Channel::UNKNOWN))));
|
||||
::testing::Values(kSeedFilesGroup, kControlGroup, std::string()))));
|
||||
} // namespace
|
||||
} // namespace variations
|
||||
|
@ -47,10 +47,10 @@ class FakeSeedStore : public VariationsSeedStore {
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state,
|
||||
version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath()),
|
||||
version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath()) {
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*entropy_provider=*/nullptr) {
|
||||
VariationsSeedStore::RegisterPrefs(local_state->registry());
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ std::unique_ptr<VariationsSeedStore> CreateSeedStore(PrefService* local_state) {
|
||||
local_state, /*initial_seed=*/nullptr,
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state, version_info::Channel::UNKNOWN,
|
||||
local_state,
|
||||
/*seed_file_dir=*/base::FilePath()),
|
||||
version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath());
|
||||
@ -366,7 +366,6 @@ class TestVariationsSeedStore : public VariationsSeedStore {
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state,
|
||||
version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath()),
|
||||
version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath()) {}
|
||||
@ -994,7 +993,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) {
|
||||
local_state(), std::move(initial_seed),
|
||||
/*signature_verification_enabled=*/false,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state(), version_info::Channel::UNKNOWN,
|
||||
local_state(),
|
||||
/*seed_file_dir=*/base::FilePath()),
|
||||
version_info::Channel::UNKNOWN, /*seed_file_dir=*/base::FilePath());
|
||||
VariationsFieldTrialCreator field_trial_creator(
|
||||
|
@ -364,10 +364,10 @@ VariationsService::VariationsService(
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(
|
||||
local_state,
|
||||
client_.get()->GetChannelForVariations(),
|
||||
client_.get()->GetVariationsSeedFileDir()),
|
||||
client_.get()->GetChannelForVariations(),
|
||||
client_.get()->GetVariationsSeedFileDir()),
|
||||
client_.get()->GetVariationsSeedFileDir(),
|
||||
entropy_providers_.get()),
|
||||
ui_string_overrider,
|
||||
&limited_entropy_synthetic_trial_) {
|
||||
DCHECK(client_);
|
||||
|
@ -19,14 +19,12 @@ const base::FilePath::CharType kSafeSeedFilename[] =
|
||||
|
||||
VariationsSafeSeedStoreLocalState::VariationsSafeSeedStoreLocalState(
|
||||
PrefService* local_state,
|
||||
const version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir)
|
||||
: local_state_(local_state),
|
||||
seed_reader_writer_(std::make_unique<SeedReaderWriter>(
|
||||
local_state,
|
||||
seed_file_dir,
|
||||
kSafeSeedFilename,
|
||||
channel,
|
||||
prefs::kVariationsSafeCompressedSeed)) {}
|
||||
|
||||
VariationsSafeSeedStoreLocalState::~VariationsSafeSeedStoreLocalState() =
|
||||
|
@ -23,12 +23,10 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSafeSeedStoreLocalState
|
||||
public:
|
||||
// |local_state| should generally be the same value that VariationsSeedStore
|
||||
// uses.
|
||||
// |channel| describes the release channel of the browser.
|
||||
// |seed_file_dir| is the file path to the seed file directory. If empty, the
|
||||
// seed is not stored in a separate seed file, only in |local_state_|.
|
||||
explicit VariationsSafeSeedStoreLocalState(
|
||||
PrefService* local_state,
|
||||
const version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir);
|
||||
|
||||
VariationsSafeSeedStoreLocalState(const VariationsSafeSeedStoreLocalState&) =
|
||||
|
@ -742,7 +742,7 @@ TYPED_TEST(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
|
||||
DISABLE_GROUP,
|
||||
};
|
||||
|
||||
const char kDefaultGroup[] = "Default";
|
||||
const char kTestDefaultGroup[] = "Default";
|
||||
const char kEnabledGroup[] = "Enabled";
|
||||
const char kDisabledGroup[] = "Disabled";
|
||||
const char kForcedOnGroup[] = "ForcedOn";
|
||||
@ -761,7 +761,7 @@ TYPED_TEST(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
|
||||
// Check what happens without and command-line forcing flags - that the
|
||||
// |one_hundred_percent_group| gets correctly selected and does the right
|
||||
// thing w.r.t. to affecting the feature / activating the trial.
|
||||
{ToRawRef(kFeatureOffByDefault), "", "", DEFAULT_GROUP, kDefaultGroup,
|
||||
{ToRawRef(kFeatureOffByDefault), "", "", DEFAULT_GROUP, kTestDefaultGroup,
|
||||
false, true},
|
||||
{ToRawRef(kFeatureOffByDefault), "", "", ENABLE_GROUP, kEnabledGroup,
|
||||
true, true},
|
||||
@ -769,7 +769,7 @@ TYPED_TEST(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
|
||||
false, true},
|
||||
|
||||
// Do the same as above, but for kFeatureOnByDefault feature.
|
||||
{ToRawRef(kFeatureOnByDefault), "", "", DEFAULT_GROUP, kDefaultGroup,
|
||||
{ToRawRef(kFeatureOnByDefault), "", "", DEFAULT_GROUP, kTestDefaultGroup,
|
||||
true, true},
|
||||
{ToRawRef(kFeatureOnByDefault), "", "", ENABLE_GROUP, kEnabledGroup, true,
|
||||
true},
|
||||
@ -829,8 +829,8 @@ TYPED_TEST(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
|
||||
VariationsSeed seed;
|
||||
Study* study = seed.add_study();
|
||||
study->set_name("Study1");
|
||||
study->set_default_experiment_name(kDefaultGroup);
|
||||
AddExperiment(kDefaultGroup, group == DEFAULT_GROUP ? 1 : 0, study);
|
||||
study->set_default_experiment_name(kTestDefaultGroup);
|
||||
AddExperiment(kTestDefaultGroup, group == DEFAULT_GROUP ? 1 : 0, study);
|
||||
|
||||
Study::Experiment* feature_enable =
|
||||
AddExperiment(kEnabledGroup, group == ENABLE_GROUP ? 1 : 0, study);
|
||||
|
@ -155,6 +155,35 @@ StoreSeedResult Uncompress(const std::string& compressed, std::string* result) {
|
||||
return StoreSeedResult::kFailedEmptyGzipContents;
|
||||
return StoreSeedResult::kSuccess;
|
||||
}
|
||||
|
||||
// Returns true if the client is eligible to participate in the seed file trial.
|
||||
bool IsEligibleForSeedFileTrial(
|
||||
version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir,
|
||||
const variations::EntropyProviders* entropy_providers) {
|
||||
// Note platforms that should not participate in the experiment will
|
||||
// deliberately pass an empty |seed_file_dir| and null |entropy_provider|.
|
||||
if (seed_file_dir.empty() || entropy_providers == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return channel == version_info::Channel::CANARY ||
|
||||
channel == version_info::Channel::DEV ||
|
||||
channel == version_info::Channel::BETA;
|
||||
}
|
||||
|
||||
// Sets up the seed file experiment which only some clients are eligible for
|
||||
// (see IsEligibleForSeedFileTrial()).
|
||||
void SetUpSeedFileTrial(
|
||||
const base::FieldTrial::EntropyProvider& entropy_provider) {
|
||||
scoped_refptr<base::FieldTrial> trial(
|
||||
base::FieldTrialList::FactoryGetFieldTrial(
|
||||
kSeedFileTrial, /*total_probability=*/100, kDefaultGroup,
|
||||
entropy_provider));
|
||||
|
||||
trial->AppendGroup(kControlGroup, /*group_probability=*/50);
|
||||
trial->AppendGroup(kSeedFilesGroup, /*group_probability=*/50);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ValidatedSeed::ValidatedSeed() = default;
|
||||
@ -169,6 +198,7 @@ VariationsSeedStore::VariationsSeedStore(
|
||||
std::unique_ptr<VariationsSafeSeedStore> safe_seed_store,
|
||||
version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir,
|
||||
const variations::EntropyProviders* entropy_providers,
|
||||
bool use_first_run_prefs)
|
||||
: local_state_(local_state),
|
||||
safe_seed_store_(std::move(safe_seed_store)),
|
||||
@ -178,8 +208,10 @@ VariationsSeedStore::VariationsSeedStore(
|
||||
local_state,
|
||||
seed_file_dir,
|
||||
kSeedFilename,
|
||||
channel,
|
||||
prefs::kVariationsCompressedSeed)) {
|
||||
if (IsEligibleForSeedFileTrial(channel, seed_file_dir, entropy_providers)) {
|
||||
SetUpSeedFileTrial(entropy_providers->default_entropy());
|
||||
}
|
||||
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
|
||||
if (initial_seed)
|
||||
ImportInitialSeed(std::move(initial_seed));
|
||||
|
@ -13,10 +13,12 @@
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/metrics/field_trial.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/version_info/channel.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
#include "components/variations/entropy_provider.h"
|
||||
#include "components/variations/metrics.h"
|
||||
#include "components/variations/proto/variations_seed.pb.h"
|
||||
#include "components/variations/seed_reader_writer.h"
|
||||
@ -68,16 +70,20 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore {
|
||||
// |channel| describes the release channel of the browser.
|
||||
// |seed_file_dir| is the file path to the seed file directory. If empty, the
|
||||
// seed is not stored in a separate seed file, only in |local_state_|.
|
||||
// |entropy_providers| used to provide entropy when setting up the seed file
|
||||
// field trial. If null, the client will not participate in the experiment.
|
||||
// |use_first_run_prefs|, if true (default), facilitates modifying Java
|
||||
// SharedPreferences ("first run prefs") on Android. If false,
|
||||
// SharedPreferences are not accessed.
|
||||
VariationsSeedStore(PrefService* local_state,
|
||||
std::unique_ptr<SeedResponse> initial_seed,
|
||||
bool signature_verification_enabled,
|
||||
std::unique_ptr<VariationsSafeSeedStore> safe_seed_store,
|
||||
version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir,
|
||||
bool use_first_run_prefs = true);
|
||||
VariationsSeedStore(
|
||||
PrefService* local_state,
|
||||
std::unique_ptr<SeedResponse> initial_seed,
|
||||
bool signature_verification_enabled,
|
||||
std::unique_ptr<VariationsSafeSeedStore> safe_seed_store,
|
||||
version_info::Channel channel,
|
||||
const base::FilePath& seed_file_dir,
|
||||
const variations::EntropyProviders* entropy_providers = nullptr,
|
||||
bool use_first_run_prefs = true);
|
||||
|
||||
VariationsSeedStore(const VariationsSeedStore&) = delete;
|
||||
VariationsSeedStore& operator=(const VariationsSeedStore&) = delete;
|
||||
|
@ -14,8 +14,10 @@
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/mock_entropy_provider.h"
|
||||
#include "base/test/protobuf_matchers.h"
|
||||
#include "base/test/scoped_command_line.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/time/time.h"
|
||||
@ -24,6 +26,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "components/prefs/testing_pref_service.h"
|
||||
#include "components/variations/client_filterable_state.h"
|
||||
#include "components/variations/entropy_provider.h"
|
||||
#include "components/variations/pref_names.h"
|
||||
#include "components/variations/proto/study.pb.h"
|
||||
#include "components/variations/proto/variations_seed.pb.h"
|
||||
@ -47,6 +50,7 @@ namespace variations {
|
||||
namespace {
|
||||
|
||||
using ::base::test::EqualsProto;
|
||||
using ::testing::IsEmpty;
|
||||
|
||||
// The sentinel value that may be stored as the latest variations seed value in
|
||||
// prefs to indicate that the latest seed is identical to the safe seed.
|
||||
@ -63,20 +67,24 @@ class TestVariationsSeedStore : public VariationsSeedStore {
|
||||
public:
|
||||
explicit TestVariationsSeedStore(
|
||||
PrefService* local_state,
|
||||
version_info::Channel channel = version_info::Channel::UNKNOWN,
|
||||
base::FilePath seed_file_dir = base::FilePath(),
|
||||
bool signature_verification_needed = false,
|
||||
std::unique_ptr<SeedResponse> initial_seed = nullptr,
|
||||
bool use_first_run_prefs = true)
|
||||
bool use_first_run_prefs = true,
|
||||
version_info::Channel channel = version_info::Channel::UNKNOWN,
|
||||
std::unique_ptr<const EntropyProviders> entropy_providers =
|
||||
std::make_unique<const MockEntropyProviders>(
|
||||
MockEntropyProviders::Results{
|
||||
.low_entropy = kAlwaysUseLastGroup}))
|
||||
: VariationsSeedStore(
|
||||
local_state,
|
||||
std::move(initial_seed),
|
||||
signature_verification_needed,
|
||||
std::make_unique<VariationsSafeSeedStoreLocalState>(local_state,
|
||||
channel,
|
||||
seed_file_dir),
|
||||
channel,
|
||||
seed_file_dir,
|
||||
entropy_providers.get(),
|
||||
use_first_run_prefs) {}
|
||||
~TestVariationsSeedStore() override = default;
|
||||
};
|
||||
@ -266,7 +274,6 @@ void CheckSafeSeedPrefsAreCleared(const TestingPrefServiceSimple& prefs) {
|
||||
prefs, prefs::kVariationsSafeSeedSessionConsistencyCountry));
|
||||
EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedSignature));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class VariationsSeedStoreTest : public ::testing::Test {
|
||||
@ -340,7 +347,7 @@ TEST_F(VariationsSeedStoreTest, LoadSeed_InvalidSignature) {
|
||||
|
||||
// Loading a valid seed with an invalid signature should return false and
|
||||
// clear all associated prefs when signature verification is enabled.
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
base::HistogramTester histogram_tester;
|
||||
@ -391,7 +398,7 @@ TEST_F(VariationsSeedStoreTest, LoadSeed_RejectEmptySignature) {
|
||||
|
||||
// Loading a valid seed with an empty signature should fail and clear all
|
||||
// associated prefs when signature verification is enabled.
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
base::HistogramTester histogram_tester;
|
||||
@ -422,7 +429,7 @@ TEST_F(VariationsSeedStoreTest, LoadSeed_AcceptEmptySignature) {
|
||||
scoped_command_line.GetProcessCommandLine()->AppendSwitch(
|
||||
switches::kAcceptEmptySeedSignatureForTesting);
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
base::HistogramTester histogram_tester;
|
||||
@ -500,27 +507,31 @@ TEST_F(VariationsSeedStoreTest, ApplyDeltaPatch) {
|
||||
}
|
||||
|
||||
struct StoreSeedDataTestParams {
|
||||
using TupleT = std::tuple<bool, version_info::Channel>;
|
||||
using TupleT = std::tuple<bool, std::string_view>;
|
||||
const bool require_synchronous_stores;
|
||||
const version_info::Channel channel;
|
||||
std::string_view field_trial_group;
|
||||
|
||||
explicit StoreSeedDataTestParams(const TupleT& t)
|
||||
: require_synchronous_stores(std::get<0>(t)), channel(std::get<1>(t)) {}
|
||||
: require_synchronous_stores(std::get<0>(t)),
|
||||
field_trial_group(std::get<1>(t)) {}
|
||||
};
|
||||
|
||||
class StoreSeedTestBase : public ::testing::Test {
|
||||
public:
|
||||
StoreSeedTestBase(std::string_view seed_pref, version_info::Channel channel)
|
||||
explicit StoreSeedTestBase(std::string_view seed_pref,
|
||||
std::string_view field_trial_group)
|
||||
: file_writer_thread_("SeedReaderWriter Test thread") {
|
||||
scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
|
||||
file_writer_thread_.Start();
|
||||
CHECK(temp_dir_.CreateUniqueTempDir());
|
||||
temp_seed_file_path_ = temp_dir_.GetPath().Append(kSeedFilename);
|
||||
|
||||
VariationsSeedStore::RegisterPrefs(prefs_.registry());
|
||||
SetUpSeedFileTrial(std::string(field_trial_group));
|
||||
|
||||
// Initialize |seed_reader_writer_| with test thread and timer.
|
||||
seed_reader_writer_ = std::make_unique<SeedReaderWriter>(
|
||||
&prefs_, temp_dir_.GetPath(), kSeedFilename, channel, seed_pref,
|
||||
&prefs_, temp_dir_.GetPath(), kSeedFilename, seed_pref,
|
||||
file_writer_thread_.task_runner());
|
||||
seed_reader_writer_->SetTimerForTesting(&timer_);
|
||||
}
|
||||
@ -528,6 +539,7 @@ class StoreSeedTestBase : public ::testing::Test {
|
||||
~StoreSeedTestBase() override = default;
|
||||
|
||||
protected:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
base::Thread file_writer_thread_;
|
||||
base::ScopedTempDir temp_dir_;
|
||||
@ -537,14 +549,89 @@ class StoreSeedTestBase : public ::testing::Test {
|
||||
std::unique_ptr<SeedReaderWriter> seed_reader_writer_;
|
||||
};
|
||||
|
||||
class StoreSeedDataChannelTest
|
||||
class ExpectedFieldTrialGroupChannelsTest
|
||||
: public StoreSeedTestBase,
|
||||
public ::testing::WithParamInterface<version_info::Channel> {
|
||||
public:
|
||||
explicit ExpectedFieldTrialGroupChannelsTest()
|
||||
: StoreSeedTestBase(
|
||||
"ignored_seed_type",
|
||||
// Note that an empty group does not force set a trial group.
|
||||
/*field_trial_group=*/std::string()) {}
|
||||
};
|
||||
|
||||
class ExpectedFieldTrialGroupAllChannelsTest
|
||||
: public ExpectedFieldTrialGroupChannelsTest {};
|
||||
class ExpectedFieldTrialGroupPreStableTest
|
||||
: public ExpectedFieldTrialGroupChannelsTest {};
|
||||
class ExpectedFieldTrialGroupStableAndUnknownTest
|
||||
: public ExpectedFieldTrialGroupChannelsTest {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
ExpectedFieldTrialGroupAllChannelsTest,
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA,
|
||||
version_info::Channel::STABLE));
|
||||
|
||||
// If empty seed file dir given, client is not assigned a group.
|
||||
TEST_P(ExpectedFieldTrialGroupAllChannelsTest, NoSeedFileDir) {
|
||||
TestVariationsSeedStore seed_store(
|
||||
&prefs_,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/false, /*initial_seed=*/nullptr,
|
||||
/*use_first_run_prefs=*/true, /*channel=*/GetParam());
|
||||
EXPECT_THAT(base::FieldTrialList::FindFullName(kSeedFileTrial), IsEmpty());
|
||||
}
|
||||
|
||||
// If no entropy provider given, client is not assigned a group.
|
||||
TEST_P(ExpectedFieldTrialGroupAllChannelsTest, NoEntropyProvider) {
|
||||
TestVariationsSeedStore seed_store(
|
||||
&prefs_, temp_dir_.GetPath(), /*signature_verification_needed=*/false,
|
||||
/*initial_seed=*/nullptr, /*use_first_run_prefs=*/true,
|
||||
/*channel=*/GetParam(), /*entropy_providers=*/nullptr);
|
||||
EXPECT_THAT(base::FieldTrialList::FindFullName(kSeedFileTrial), IsEmpty());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
ExpectedFieldTrialGroupPreStableTest,
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA));
|
||||
|
||||
// If channel is pre-stable, client is assigned a group.
|
||||
TEST_P(ExpectedFieldTrialGroupPreStableTest, PreStable) {
|
||||
TestVariationsSeedStore seed_store(
|
||||
&prefs_, temp_dir_.GetPath(), /*signature_verification_needed=*/false,
|
||||
/*initial_seed=*/nullptr, /*use_first_run_prefs=*/true,
|
||||
/*channel=*/GetParam());
|
||||
EXPECT_THAT(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
::testing::AnyOf(kControlGroup, kSeedFilesGroup));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
ExpectedFieldTrialGroupStableAndUnknownTest,
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::STABLE));
|
||||
|
||||
// If channel is stable or unknown, client is not assigned a group.
|
||||
TEST_P(ExpectedFieldTrialGroupStableAndUnknownTest, StableAndUnknown) {
|
||||
TestVariationsSeedStore seed_store(
|
||||
&prefs_, temp_dir_.GetPath(), /*signature_verification_needed=*/false,
|
||||
/*initial_seed=*/nullptr, /*use_first_run_prefs=*/true,
|
||||
/*channel=*/GetParam());
|
||||
EXPECT_THAT(base::FieldTrialList::FindFullName(kSeedFileTrial), IsEmpty());
|
||||
}
|
||||
|
||||
class StoreSeedDataGroupTest
|
||||
: public StoreSeedTestBase,
|
||||
public ::testing::WithParamInterface<StoreSeedDataTestParams> {
|
||||
public:
|
||||
StoreSeedDataChannelTest()
|
||||
explicit StoreSeedDataGroupTest()
|
||||
: StoreSeedTestBase(prefs::kVariationsCompressedSeed,
|
||||
GetParam().channel) {}
|
||||
~StoreSeedDataChannelTest() override = default;
|
||||
GetParam().field_trial_group) {}
|
||||
~StoreSeedDataGroupTest() override = default;
|
||||
|
||||
bool RequireSynchronousStores() const {
|
||||
return GetParam().require_synchronous_stores;
|
||||
@ -567,7 +654,7 @@ class StoreSeedDataChannelTest
|
||||
seed_data, /*base64_seed_signature=*/std::string(), params.country_code,
|
||||
base::Time::Now(), params.is_delta_compressed,
|
||||
params.is_gzip_compressed,
|
||||
base::BindOnce(&StoreSeedDataChannelTest::OnSeedStoreResult,
|
||||
base::BindOnce(&StoreSeedDataGroupTest::OnSeedStoreResult,
|
||||
base::Unretained(this), run_loop.QuitClosure()),
|
||||
RequireSynchronousStores());
|
||||
// If we're testing synchronous stores, we shouldn't issue a Run() call so
|
||||
@ -591,27 +678,27 @@ class StoreSeedDataChannelTest
|
||||
}
|
||||
};
|
||||
|
||||
class StoreSeedDataPreStableTest : public StoreSeedDataChannelTest {};
|
||||
class StoreSeedDataSeedFilesGroupTest : public StoreSeedDataGroupTest {};
|
||||
|
||||
class StoreSeedDataStableAndUnknownTest : public StoreSeedDataChannelTest {};
|
||||
class StoreSeedDataControlAndLocalStateOnlyGroupTest
|
||||
: public StoreSeedDataGroupTest {};
|
||||
|
||||
class StoreSeedDataAllChannelsTest : public StoreSeedDataChannelTest {};
|
||||
class StoreSeedDataAllGroupsTest : public StoreSeedDataGroupTest {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
StoreSeedData,
|
||||
StoreSeedDataPreStableTest,
|
||||
All,
|
||||
StoreSeedDataSeedFilesGroupTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA))));
|
||||
::testing::Values(kSeedFilesGroup))));
|
||||
|
||||
// Verifies that pre-stable clients write latest seeds to local state prefs and
|
||||
// a seed file.
|
||||
TEST_P(StoreSeedDataPreStableTest, StoreSeedData) {
|
||||
// Verifies that clients in SeedFiles trial group write latest seeds to
|
||||
// local state prefs and a seed file.
|
||||
TEST_P(StoreSeedDataSeedFilesGroupTest, StoreSeedData) {
|
||||
// Initialize SeedStore with test local state prefs and SeedReaderWriter.
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
seed_store.SetSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
|
||||
// Store seed and force write for SeedReaderWriter.
|
||||
@ -632,18 +719,18 @@ TEST_P(StoreSeedDataPreStableTest, StoreSeedData) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
StoreSeedDataStableAndUnknownTest,
|
||||
StoreSeedDataControlAndLocalStateOnlyGroupTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::STABLE))));
|
||||
::testing::Values(kControlGroup, std::string()))));
|
||||
|
||||
// Verifies that stable and unknown channel clients write latest seeds only to
|
||||
// local state prefs.
|
||||
TEST_P(StoreSeedDataStableAndUnknownTest, StoreSeedData) {
|
||||
// Verifies that clients in the control group and those using local state only
|
||||
// write latest seeds only to local state prefs.
|
||||
TEST_P(StoreSeedDataControlAndLocalStateOnlyGroupTest, StoreSeedData) {
|
||||
// Initialize SeedStore with test local state prefs and SeedReaderWriter.
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
seed_store.SetSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
|
||||
const std::string serialized_seed = SerializeSeed(CreateTestSeed());
|
||||
@ -660,20 +747,18 @@ TEST_P(StoreSeedDataStableAndUnknownTest, StoreSeedData) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
StoreSeedDataAllChannelsTest,
|
||||
StoreSeedDataAllGroupsTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA,
|
||||
version_info::Channel::STABLE))));
|
||||
::testing::Combine(
|
||||
::testing::Bool(),
|
||||
::testing::Values(kSeedFilesGroup, kControlGroup, std::string()))));
|
||||
|
||||
// Verifies that invalid latest seeds are not stored.
|
||||
TEST_P(StoreSeedDataAllChannelsTest, StoreSeedData_InvalidSeed) {
|
||||
// Initialize SeedStore with test local state prefs and SeedReaderWriter.
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, StoreSeedData_InvalidSeed) {
|
||||
// Initialize SeedStore with test prefs and SeedReaderWriter.
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
seed_store.SetSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
|
||||
// Check if trying to store a bad seed leaves the local state prefs unchanged.
|
||||
@ -685,18 +770,20 @@ TEST_P(StoreSeedDataAllChannelsTest, StoreSeedData_InvalidSeed) {
|
||||
EXPECT_FALSE(base::PathExists(temp_seed_file_path_));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, ParsedSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, ParsedSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
const std::string serialized_seed = SerializeSeed(CreateTestSeed());
|
||||
ASSERT_TRUE(StoreSeedData(seed_store, serialized_seed));
|
||||
EXPECT_EQ(serialized_seed, SerializeSeed(stored_seed_));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, CountryCode) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, CountryCode) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
// Test with a valid header value.
|
||||
std::string seed = SerializeSeed(CreateTestSeed());
|
||||
@ -709,9 +796,10 @@ TEST_P(StoreSeedDataAllChannelsTest, CountryCode) {
|
||||
EXPECT_EQ("test_country", prefs_.GetString(prefs::kVariationsCountry));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, GzippedSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, GzippedSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
const std::string serialized_seed = SerializeSeed(CreateTestSeed());
|
||||
ASSERT_TRUE(StoreSeedData(seed_store, Gzip(serialized_seed),
|
||||
@ -719,35 +807,38 @@ TEST_P(StoreSeedDataAllChannelsTest, GzippedSeed) {
|
||||
EXPECT_EQ(serialized_seed, SerializeSeed(stored_seed_));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, GzippedEmptySeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, GzippedEmptySeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
store_success_ = true;
|
||||
EXPECT_FALSE(StoreSeedData(seed_store, Gzip(/*data=*/std::string()),
|
||||
{.is_gzip_compressed = true}));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, DeltaCompressed) {
|
||||
TEST_P(StoreSeedDataAllGroupsTest, DeltaCompressed) {
|
||||
prefs_.SetString(prefs::kVariationsCompressedSeed,
|
||||
kSeedDeltaTestData.GetInitialSeedDataAsPrefValue());
|
||||
prefs_.SetString(prefs::kVariationsSeedSignature, "ignored signature");
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
ASSERT_TRUE(StoreSeedData(seed_store, kSeedDeltaTestData.GetDeltaData(),
|
||||
{.is_delta_compressed = true}));
|
||||
EXPECT_EQ(kSeedDeltaTestData.GetNewSeedData(), SerializeSeed(stored_seed_));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, DeltaCompressedGzipped) {
|
||||
TEST_P(StoreSeedDataAllGroupsTest, DeltaCompressedGzipped) {
|
||||
prefs_.SetString(prefs::kVariationsCompressedSeed,
|
||||
kSeedDeltaTestData.GetInitialSeedDataAsPrefValue());
|
||||
prefs_.SetString(prefs::kVariationsSeedSignature, "ignored signature");
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
ASSERT_TRUE(StoreSeedData(seed_store, Gzip(kSeedDeltaTestData.GetDeltaData()),
|
||||
{
|
||||
@ -757,9 +848,10 @@ TEST_P(StoreSeedDataAllChannelsTest, DeltaCompressedGzipped) {
|
||||
EXPECT_EQ(kSeedDeltaTestData.GetNewSeedData(), SerializeSeed(stored_seed_));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, DeltaButNoInitialSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TEST_P(StoreSeedDataAllGroupsTest, DeltaButNoInitialSeed) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
store_success_ = true;
|
||||
EXPECT_FALSE(StoreSeedData(seed_store,
|
||||
@ -770,13 +862,14 @@ TEST_P(StoreSeedDataAllChannelsTest, DeltaButNoInitialSeed) {
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, BadDelta) {
|
||||
TEST_P(StoreSeedDataAllGroupsTest, BadDelta) {
|
||||
prefs_.SetString(prefs::kVariationsCompressedSeed,
|
||||
kSeedDeltaTestData.GetInitialSeedDataAsPrefValue());
|
||||
prefs_.SetString(prefs::kVariationsSeedSignature, "ignored signature");
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
store_success_ = true;
|
||||
// Provide a gzipped delta, when gzip is not expected.
|
||||
@ -785,15 +878,16 @@ TEST_P(StoreSeedDataAllChannelsTest, BadDelta) {
|
||||
{.is_delta_compressed = true}));
|
||||
}
|
||||
|
||||
TEST_P(StoreSeedDataAllChannelsTest, IdenticalToSafeSeed) {
|
||||
TEST_P(StoreSeedDataAllGroupsTest, IdenticalToSafeSeed) {
|
||||
const VariationsSeed seed = CreateTestSeed();
|
||||
const std::string serialized_seed = SerializeSeed(seed);
|
||||
|
||||
prefs_.SetString(prefs::kVariationsSafeCompressedSeed,
|
||||
SerializeSeedBase64(seed));
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
ASSERT_TRUE(StoreSeedData(seed_store, serialized_seed));
|
||||
|
||||
// Verify that the pref has a sentinel value, rather than the full string.
|
||||
@ -813,7 +907,7 @@ TEST_P(StoreSeedDataAllChannelsTest, IdenticalToSafeSeed) {
|
||||
|
||||
// Verifies that the cached serial number is correctly updated when a new seed
|
||||
// is saved.
|
||||
TEST_P(StoreSeedDataAllChannelsTest,
|
||||
TEST_P(StoreSeedDataAllGroupsTest,
|
||||
GetLatestSerialNumber_UpdatedWithNewStoredSeed) {
|
||||
// Store good seed data initially.
|
||||
prefs_.SetString(prefs::kVariationsCompressedSeed,
|
||||
@ -822,8 +916,9 @@ TEST_P(StoreSeedDataAllChannelsTest,
|
||||
"a completely ignored signature");
|
||||
|
||||
// Call GetLatestSerialNumber() once to prime the cached value.
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
EXPECT_EQ("123", seed_store.GetLatestSerialNumber());
|
||||
|
||||
VariationsSeed new_seed = CreateTestSeed();
|
||||
@ -935,7 +1030,7 @@ TEST_F(VariationsSeedStoreTest, LoadSafeSeed_InvalidSignature) {
|
||||
|
||||
// Attempt to load a valid safe seed with an invalid signature while signature
|
||||
// verification is enabled.
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
base::HistogramTester histogram_tester;
|
||||
@ -988,13 +1083,13 @@ struct InvalidSafeSeedTestParams {
|
||||
};
|
||||
|
||||
struct StoreInvalidSafeSeedTestParams {
|
||||
using TupleT = std::tuple<InvalidSafeSeedTestParams, version_info::Channel>;
|
||||
using TupleT = std::tuple<InvalidSafeSeedTestParams, std::string_view>;
|
||||
|
||||
InvalidSafeSeedTestParams invalid_params;
|
||||
version_info::Channel channel;
|
||||
std::string_view field_trial_group;
|
||||
|
||||
explicit StoreInvalidSafeSeedTestParams(const TupleT& t)
|
||||
: invalid_params(std::get<0>(t)), channel(std::get<1>(t)) {}
|
||||
: invalid_params(std::get<0>(t)), field_trial_group(std::get<1>(t)) {}
|
||||
};
|
||||
|
||||
class StoreInvalidSafeSeedTest
|
||||
@ -1003,7 +1098,7 @@ class StoreInvalidSafeSeedTest
|
||||
public:
|
||||
StoreInvalidSafeSeedTest()
|
||||
: StoreSeedTestBase(prefs::kVariationsSafeCompressedSeed,
|
||||
GetParam().channel) {}
|
||||
GetParam().field_trial_group) {}
|
||||
~StoreInvalidSafeSeedTest() override = default;
|
||||
};
|
||||
|
||||
@ -1031,24 +1126,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
.store_seed_result = StoreSeedResult::kFailedSignature,
|
||||
.verify_signature_result =
|
||||
VerifySignatureResult::INVALID_SEED}),
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA,
|
||||
version_info::Channel::STABLE,
|
||||
version_info::Channel::UNKNOWN))),
|
||||
::testing::Values(kSeedFilesGroup, kControlGroup, std::string()))),
|
||||
[](const ::testing::TestParamInfo<StoreInvalidSafeSeedTestParams>& params) {
|
||||
switch (params.param.channel) {
|
||||
case version_info::Channel::CANARY:
|
||||
return params.param.invalid_params.test_name + "_" + "CANARY";
|
||||
case version_info::Channel::DEV:
|
||||
return params.param.invalid_params.test_name + "_" + "DEV";
|
||||
case version_info::Channel::BETA:
|
||||
return params.param.invalid_params.test_name + "_" + "BETA";
|
||||
case version_info::Channel::STABLE:
|
||||
return params.param.invalid_params.test_name + "_" + "STABLE";
|
||||
default:
|
||||
return params.param.invalid_params.test_name + "_" + "UNKNOWN";
|
||||
if (params.param.field_trial_group.empty()) {
|
||||
return params.param.invalid_params.test_name + "_LocalStateOnly";
|
||||
}
|
||||
return params.param.invalid_params.test_name + "_" +
|
||||
std::string(params.param.field_trial_group);
|
||||
});
|
||||
|
||||
// Verify that attempting to store an invalid safe seed fails and does not
|
||||
@ -1093,9 +1177,10 @@ TEST_P(StoreInvalidSafeSeedTest, StoreSafeSeed) {
|
||||
client_state->reference_date = now - base::Days(1);
|
||||
prefs_.SetTime(prefs::kVariationsSafeSeedDate, expected_date);
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, version_info::Channel::UNKNOWN,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
seed_store.SetSafeSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
@ -1140,31 +1225,32 @@ TEST_P(StoreInvalidSafeSeedTest, StoreSafeSeed) {
|
||||
}
|
||||
}
|
||||
|
||||
class StoreSafeSeedDataChannelTest
|
||||
class StoreSafeSeedDataGroupTest
|
||||
: public StoreSeedTestBase,
|
||||
public ::testing::WithParamInterface<StoreSeedDataTestParams> {
|
||||
public:
|
||||
StoreSafeSeedDataChannelTest()
|
||||
StoreSafeSeedDataGroupTest()
|
||||
: StoreSeedTestBase(prefs::kVariationsSafeCompressedSeed,
|
||||
GetParam().channel) {}
|
||||
~StoreSafeSeedDataChannelTest() override = default;
|
||||
GetParam().field_trial_group) {}
|
||||
~StoreSafeSeedDataGroupTest() override = default;
|
||||
};
|
||||
|
||||
class StoreSafeSeedDataPreStableTest : public StoreSafeSeedDataChannelTest {};
|
||||
class StoreSafeSeedDataStableAndUnknownTest
|
||||
: public StoreSafeSeedDataChannelTest {};
|
||||
class StoreSafeSeedDataAllChannelsTest : public StoreSafeSeedDataChannelTest {};
|
||||
class StoreSafeSeedDataSeedFilesGroupTest : public StoreSafeSeedDataGroupTest {
|
||||
};
|
||||
|
||||
class StoreSafeSeedDataControlAndLocalStateOnlyGroupTest
|
||||
: public StoreSafeSeedDataGroupTest {};
|
||||
|
||||
class StoreSafeSeedDataAllGroupsTest : public StoreSafeSeedDataGroupTest {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
StoreSafeSeedDataPreStableTest,
|
||||
StoreSafeSeedDataSeedFilesGroupTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA))));
|
||||
::testing::Values(kSeedFilesGroup))));
|
||||
|
||||
TEST_P(StoreSafeSeedDataPreStableTest, StoreSafeSeed_ValidSignature) {
|
||||
TEST_P(StoreSafeSeedDataSeedFilesGroupTest, StoreSafeSeed_ValidSignature) {
|
||||
auto client_state = CreateDummyClientFilterableState();
|
||||
const std::string expected_locale = "en-US";
|
||||
client_state->locale = expected_locale;
|
||||
@ -1178,9 +1264,10 @@ TEST_P(StoreSafeSeedDataPreStableTest, StoreSafeSeed_ValidSignature) {
|
||||
client_state->session_consistency_country =
|
||||
expected_session_consistency_country;
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath(),
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
base::HistogramTester histogram_tester;
|
||||
seed_store.SetSafeSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
|
||||
@ -1236,13 +1323,13 @@ TEST_P(StoreSafeSeedDataPreStableTest, StoreSafeSeed_ValidSignature) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
StoreSafeSeedDataStableAndUnknownTest,
|
||||
StoreSafeSeedDataControlAndLocalStateOnlyGroupTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::STABLE))));
|
||||
::testing::Values(kControlGroup, std::string()))));
|
||||
|
||||
TEST_P(StoreSafeSeedDataStableAndUnknownTest, StoreSafeSeed_ValidSignature) {
|
||||
TEST_P(StoreSafeSeedDataControlAndLocalStateOnlyGroupTest,
|
||||
StoreSafeSeed_ValidSignature) {
|
||||
std::string expected_seed;
|
||||
ASSERT_TRUE(base::Base64Decode(kTestSeedData.base64_uncompressed_data,
|
||||
&expected_seed));
|
||||
@ -1264,9 +1351,10 @@ TEST_P(StoreSafeSeedDataStableAndUnknownTest, StoreSafeSeed_ValidSignature) {
|
||||
const base::Time expected_fetch_time = now - base::Hours(6);
|
||||
|
||||
// Initialize SeedStore with test prefs and SeedReaderWriter.
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath(),
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
base::HistogramTester histogram_tester;
|
||||
seed_store.SetSafeSeedReaderWriterForTesting(std::move(seed_reader_writer_));
|
||||
|
||||
@ -1313,16 +1401,13 @@ TEST_P(StoreSafeSeedDataStableAndUnknownTest, StoreSafeSeed_ValidSignature) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
StoreSafeSeedDataAllChannelsTest,
|
||||
StoreSafeSeedDataAllGroupsTest,
|
||||
::testing::ConvertGenerator<StoreSeedDataTestParams::TupleT>(
|
||||
::testing::Combine(::testing::Bool(),
|
||||
::testing::Values(version_info::Channel::UNKNOWN,
|
||||
version_info::Channel::CANARY,
|
||||
version_info::Channel::DEV,
|
||||
version_info::Channel::BETA,
|
||||
version_info::Channel::STABLE))));
|
||||
::testing::Combine(
|
||||
::testing::Bool(),
|
||||
::testing::Values(kSeedFilesGroup, kControlGroup, std::string()))));
|
||||
|
||||
TEST_P(StoreSafeSeedDataAllChannelsTest, StoreSafeSeed_IdenticalToLatestSeed) {
|
||||
TEST_P(StoreSafeSeedDataAllGroupsTest, StoreSafeSeed_IdenticalToLatestSeed) {
|
||||
const VariationsSeed seed = CreateTestSeed();
|
||||
const std::string serialized_seed = SerializeSeed(seed);
|
||||
const std::string base64_seed = SerializeSeedBase64(seed);
|
||||
@ -1332,8 +1417,9 @@ TEST_P(StoreSafeSeedDataAllChannelsTest, StoreSafeSeed_IdenticalToLatestSeed) {
|
||||
const base::Time last_fetch_time = WrapTime(99999);
|
||||
prefs_.SetTime(prefs::kVariationsLastFetchTime, last_fetch_time);
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
base::HistogramTester histogram_tester;
|
||||
ASSERT_TRUE(seed_store.StoreSafeSeed(
|
||||
serialized_seed, "a completely ignored signature", /*seed_milestone=*/92,
|
||||
@ -1369,7 +1455,7 @@ TEST_P(StoreSafeSeedDataAllChannelsTest, StoreSafeSeed_IdenticalToLatestSeed) {
|
||||
"Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::kSuccess, 1);
|
||||
}
|
||||
|
||||
TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
TEST_P(StoreSafeSeedDataAllGroupsTest,
|
||||
StoreSafeSeed_PreviouslyIdenticalToLatestSeed) {
|
||||
// Create two distinct seeds: an old one saved as both the safe and the latest
|
||||
// seed value, and a new one that should overwrite only the stored safe seed
|
||||
@ -1387,8 +1473,9 @@ TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
prefs_.SetString(prefs::kVariationsCompressedSeed,
|
||||
kIdenticalToSafeSeedSentinel);
|
||||
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath());
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath());
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
base::HistogramTester histogram_tester;
|
||||
ASSERT_TRUE(seed_store.StoreSafeSeed(
|
||||
SerializeSeed(new_seed), "a completely ignored signature",
|
||||
@ -1446,7 +1533,7 @@ TEST_F(VariationsSeedStoreTest, VerifySeedSignature) {
|
||||
{
|
||||
prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data);
|
||||
prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature);
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
|
||||
@ -1466,7 +1553,7 @@ TEST_F(VariationsSeedStoreTest, VerifySeedSignature) {
|
||||
{
|
||||
prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data);
|
||||
prefs.SetString(prefs::kVariationsSeedSignature, std::string());
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
|
||||
@ -1487,7 +1574,7 @@ TEST_F(VariationsSeedStoreTest, VerifySeedSignature) {
|
||||
prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data);
|
||||
prefs.SetString(prefs::kVariationsSeedSignature,
|
||||
"not a base64-encoded string");
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
|
||||
@ -1509,7 +1596,7 @@ TEST_F(VariationsSeedStoreTest, VerifySeedSignature) {
|
||||
{
|
||||
prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed_data);
|
||||
prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_data);
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
|
||||
@ -1536,7 +1623,7 @@ TEST_F(VariationsSeedStoreTest, VerifySeedSignature) {
|
||||
|
||||
prefs.SetString(prefs::kVariationsCompressedSeed, base64_wrong_seed_data);
|
||||
prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature);
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
|
||||
@ -1764,7 +1851,7 @@ TEST_P(VariationsSeedStoreFirstRunPrefsTest, FirstRunPrefsAllowed) {
|
||||
|
||||
TestingPrefServiceSimple prefs;
|
||||
VariationsSeedStore::RegisterPrefs(prefs.registry());
|
||||
TestVariationsSeedStore seed_store(&prefs, version_info::Channel::UNKNOWN,
|
||||
TestVariationsSeedStore seed_store(&prefs,
|
||||
/*seed_file_dir=*/base::FilePath(),
|
||||
/*signature_verification_needed=*/false,
|
||||
/*initial_seed=*/std::move(seed),
|
||||
@ -1862,11 +1949,12 @@ void ExpectSafeSeed(const featured::SeedDetails& platform,
|
||||
EXPECT_EQ(platform.fetch_time(), expected.fetch_time());
|
||||
}
|
||||
|
||||
TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
TEST_P(StoreSafeSeedDataAllGroupsTest,
|
||||
SendSafeSeedToPlatform_SucceedFirstAttempt) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath(),
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
ash::featured::FeaturedClient::InitializeFake();
|
||||
ash::featured::FakeFeaturedClient* client =
|
||||
@ -1894,11 +1982,12 @@ TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
ash::featured::FeaturedClient::Shutdown();
|
||||
}
|
||||
|
||||
TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
TEST_P(StoreSafeSeedDataAllGroupsTest,
|
||||
SendSafeSeedToPlatform_FailFirstAttempt) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath(),
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
ash::featured::FeaturedClient::InitializeFake();
|
||||
ash::featured::FakeFeaturedClient* client =
|
||||
@ -1927,11 +2016,11 @@ TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
ash::featured::FeaturedClient::Shutdown();
|
||||
}
|
||||
|
||||
TEST_P(StoreSafeSeedDataAllChannelsTest,
|
||||
SendSafeSeedToPlatform_FailTwoAttempts) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, GetParam().channel,
|
||||
temp_dir_.GetPath(),
|
||||
TEST_P(StoreSafeSeedDataAllGroupsTest, SendSafeSeedToPlatform_FailTwoAttempts) {
|
||||
TestVariationsSeedStore seed_store(&prefs_, temp_dir_.GetPath(),
|
||||
/*signature_verification_needed=*/true);
|
||||
ASSERT_EQ(base::FieldTrialList::FindFullName(kSeedFileTrial),
|
||||
GetParam().field_trial_group);
|
||||
|
||||
ash::featured::FeaturedClient::InitializeFake();
|
||||
ash::featured::FakeFeaturedClient* client =
|
||||
|
@ -375,4 +375,18 @@ bool ContainsTrialAndGroupName(
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetUpSeedFileTrial(std::string group_name) {
|
||||
if (group_name.empty()) {
|
||||
return;
|
||||
}
|
||||
base::MockEntropyProvider entropy_provider(0.9);
|
||||
scoped_refptr<base::FieldTrial> trial(
|
||||
base::FieldTrialList::FactoryGetFieldTrial(
|
||||
kSeedFileTrial, /*total_probability=*/100, kDefaultGroup,
|
||||
entropy_provider));
|
||||
|
||||
trial->AppendGroup(group_name, /*group_probability=*/100);
|
||||
trial->SetForced();
|
||||
}
|
||||
|
||||
} // namespace variations
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "components/variations/entropy_provider.h"
|
||||
#include "components/variations/field_trial_config/fieldtrial_testing_config.h"
|
||||
#include "components/variations/proto/variations_seed.pb.h"
|
||||
#include "components/variations/seed_reader_writer.h"
|
||||
#include "components/variations/synthetic_trial_registry.h"
|
||||
#include "components/variations/variations_associated_data.h"
|
||||
|
||||
@ -164,6 +165,9 @@ bool ContainsTrialAndGroupName(
|
||||
std::string_view trial_name,
|
||||
std::string_view group_name);
|
||||
|
||||
// Sets up the seed file experiment where `group_name` is the active group.
|
||||
void SetUpSeedFileTrial(std::string group_name);
|
||||
|
||||
} // namespace variations
|
||||
|
||||
#endif // COMPONENTS_VARIATIONS_VARIATIONS_TEST_UTILS_H_
|
||||
|
@ -903,7 +903,6 @@ void ShellContentBrowserClient::SetUpFieldTrials() {
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<variations::VariationsSafeSeedStoreLocalState>(
|
||||
GetSharedState().local_state.get(),
|
||||
variations_service_client.GetChannelForVariations(),
|
||||
variations_service_client.GetVariationsSeedFileDir()),
|
||||
variations_service_client.GetChannelForVariations(),
|
||||
variations_service_client.GetVariationsSeedFileDir()),
|
||||
|
@ -106,7 +106,7 @@ void SetUpFieldTrials(PrefService* local_state,
|
||||
local_state, /*initial_seed=*/nullptr,
|
||||
/*signature_verification_enabled=*/true,
|
||||
std::make_unique<variations::VariationsSafeSeedStoreLocalState>(
|
||||
local_state, variations_service_client.GetChannelForVariations(),
|
||||
local_state,
|
||||
variations_service_client.GetVariationsSeedFileDir()),
|
||||
variations_service_client.GetChannelForVariations(),
|
||||
variations_service_client.GetVariationsSeedFileDir()),
|
||||
|
Reference in New Issue
Block a user