blob: 9dc529a0f4ef0ddb4af4482751c18faf63d122a4 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2020 The Chromium Authors
Karthika Paia264586a2020-10-27 23:32:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/variations/variations_test_utils.h"
6
Karthika Paia264586a2020-10-27 23:32:017#include "base/base64.h"
Caitlin Fischer6920a082021-06-29 05:25:248#include "base/command_line.h"
Karthika Paia264586a2020-10-27 23:32:019#include "base/feature_list.h"
Yulun Zeng29c77e5d2024-02-16 02:24:5610#include "base/time/time.h"
Roger McFarlane3da6db2732021-10-06 13:41:0411#include "components/metrics/clean_exit_beacon.h"
12#include "components/metrics/metrics_pref_names.h"
13#include "components/prefs/pref_service.h"
Yulun Zeng29c77e5d2024-02-16 02:24:5614#include "components/variations/active_field_trials.h"
Steven Holtef08a3362022-09-15 07:33:0615#include "components/variations/client_filterable_state.h"
Luc Nguyen1180c662022-02-08 20:38:5916#include "components/variations/field_trial_config/fieldtrial_testing_config.h"
Yulun Zeng29c77e5d2024-02-16 02:24:5617#include "components/variations/hashing.h"
Roger McFarlane3da6db2732021-10-06 13:41:0418#include "components/variations/pref_names.h"
Karthika Paia264586a2020-10-27 23:32:0119#include "components/variations/proto/client_variations.pb.h"
Yulun Zeng29c77e5d2024-02-16 02:24:5620#include "components/variations/synthetic_trial_registry.h"
Karthika Paia264586a2020-10-27 23:32:0121#include "components/variations/variations_associated_data.h"
Caitlin Fischer6920a082021-06-29 05:25:2422#include "components/variations/variations_switches.h"
Caitlin Fischerd7651aed2021-07-13 03:20:4023#include "third_party/zlib/google/compression_utils.h"
Karthika Paia264586a2020-10-27 23:32:0124
25namespace variations {
Roger McFarlane3da6db2732021-10-06 13:41:0426namespace {
Karthika Paia264586a2020-10-27 23:32:0127
Steven Holtee34ff1a2022-09-15 00:06:5628// kTestSeed is a simple VariationsSeed containing:
29// serial_number: "test"
30// study: {
31// name: "UMA-Uniformity-Trial-50-Percent"
32// consistency: PERMANENT
33// experiment: {
34// name: "default"
35// probability_weight: 1
36// }
37// experiment: {
38// name: "group_01"
39// probability_weight: 1
40// }
41// }
42
43const char* kTestSeed_StudyNames[] = {"UMA-Uniformity-Trial-50-Percent"};
Roger McFarlane3da6db2732021-10-06 13:41:0444
45const char kTestSeed_Base64UncompressedData[] =
Steven Holtee34ff1a2022-09-15 00:06:5646 "CgR0ZXN0Ej4KH1VNQS1Vbmlmb3JtaXR5LVRyaWFsLTUwLVBlcmNlbnQ4AUoLCgdkZWZhdWx0EA"
47 "FKDAoIZ3JvdXBfMDEQAQ==";
Caitlin Fischer7b55ee12021-07-14 16:05:2948
Roger McFarlane3da6db2732021-10-06 13:41:0449const char kTestSeed_Base64CompressedData[] =
Steven Holtee34ff1a2022-09-15 00:06:5650 "H4sIAAAAAAAA/+JiKUktLhGy45IP9XXUDc3LTMsvys0sqdQNKcpMzNE1NdANSC1KTs0rsWD04u"
51 "ZiT0lNSyzNKRFg9OLh4kgvyi8tiDcwFGAEBAAA//90/JgERgAAAA==";
Caitlin Fischer6920a082021-06-29 05:25:2452
Roger McFarlane3da6db2732021-10-06 13:41:0453const char kTestSeed_Base64Signature[] =
Steven Holtee34ff1a2022-09-15 00:06:5654 "MEUCIQD5AEAzk5qEuE3xOZl+xSZR15Ac1RJpsXMiou7i5W0sMAIgRn++ngh03HaMGC+Pjl9NOu"
55 "Doxf83qsSwycF2PSS1nYQ=";
Caitlin Fischer6920a082021-06-29 05:25:2456
Roger McFarlane3da6db2732021-10-06 13:41:0457const char* kCrashingSeed_StudyNames[] = {"CrashingStudy"};
58
Steven Holtee34ff1a2022-09-15 00:06:5659// kCrashingSeed is a VariationsSeed that triggers a crash for testing:
60// serial_number: "35ed2d9e354b414befdf930a734094019c0162f1"
61// study: {
62// name: "CrashingStudy"
63// consistency: PERMANENT
64// experiment: {
65// name: "EnabledLaunch"
66// probability_weight: 100
67// feature_association: {
68// enable_feature: "ForceFieldTrialSetupCrashForTesting"
69// }
70// }
71// experiment: {
72// name: "ForcedOn_ForceFieldTrialSetupCrashForTesting"
73// probability_weight: 0
74// feature_association: {
75// forcing_feature_on: "ForceFieldTrialSetupCrashForTesting"
76// }
77// }
78// experiment: {
79// name: "ForcedOff_ForceFieldTrialSetupCrashForTesting"
80// probability_weight: 0
81// feature_association: {
82// forcing_feature_off: "ForceFieldTrialSetupCrashForTesting"
83// }
84// }
85// filter: {
86// min_version: "91.*"
87// channel: CANARY
88// channel: DEV
89// channel: BETA
90// channel: STABLE
91// platform: PLATFORM_ANDROID
92// platform: PLATFORM_IOS
93// platform: PLATFORM_ANDROID_WEBVIEW
94// platform: PLATFORM_WINDOWS
95// platform: PLATFORM_MAC
96// platform: PLATFORM_LINUX
97// platform: PLATFORM_CHROMEOS
98// platform: PLATFORM_CHROMEOS_LACROS
99// }
100// }
101// version: "hash/4aa56a1dc30dfc767615248d6fee29830198b276"
102
Roger McFarlane3da6db2732021-10-06 13:41:04103const char kCrashingSeed_Base64UncompressedData[] =
104 "CigzNWVkMmQ5ZTM1NGI0MTRiZWZkZjkzMGE3MzQwOTQwMTljMDE2MmYxEp4CCg1DcmFzaGluZ1"
105 "N0dWR5OAFKOAoNRW5hYmxlZExhdW5jaBBkYiUKI0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hG"
106 "b3JUZXN0aW5nSlcKLEZvcmNlZE9uX0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hGb3JUZXN0aW"
107 "5nEABiJRojRm9yY2VGaWVsZFRyaWFsU2V0dXBDcmFzaEZvclRlc3RpbmdKWAotRm9yY2VkT2Zm"
108 "X0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hGb3JUZXN0aW5nEABiJSIjRm9yY2VGaWVsZFRyaW"
109 "FsU2V0dXBDcmFzaEZvclRlc3RpbmdSHhIEOTEuKiAAIAEgAiADKAQoBSgGKAAoASgCKAMoCSIt"
110 "aGFzaC80YWE1NmExZGMzMGRmYzc2NzYxNTI0OGQ2ZmVlMjk4MzAxOThiMjc2";
111
112const char kCrashingSeed_Base64CompressedData[] =
113 "H4sIAAAAAAAAAI3QwUvDMBTH8babwgKDsaMHKZNBEKdJk6bJWbbDEAQ30JskeS+2UKp07cF/"
114 "Zn+rZfgH9Py+73P4ESpyhAwMilw6yaXDAMEIZgshmZGMG8+4ygJfnhMyf27tqayar0PXw6+"
115 "O95rMt411NcKL7RtfLsCtyd3uu/W4q7CGY1vZ+oBd/"
116 "3P5HA5HPHUDsH8nD5cMXpvPEf0icuubUfAH2fzDIYyVV2Pkt9vl1PDH+zRK4zRJJ3RKr+"
117 "g1jWhMEzqhs9WmHPonaW2uLAcvGARfqELxPJMaVEDMjBbDotplhfoDs9NLbnoBAAA=";
118
119const char kCrashingSeed_Base64Signature[] =
120 "MEQCIEn1+VsBfNA93dxzpk+BLhdO91kMQnofxfTK5Uo8vDi8AiAnTCFCIPgEGWNOKzuKfNWn6"
121 "emB6pnGWjSTbI/pvfxHnw==";
122
Luc Nguyen1180c662022-02-08 20:38:59123// Create mock testing config equivalent to:
124// {
125// "UnitTest": [
126// {
127// "platforms": [
128// "android",
129// "android_weblayer",
130// "android_webview",
131// "chromeos",
132// "chromeos_lacros",
133// "fuchsia",
134// "ios",
135// "linux",
136// "mac",
137// "windows"
138// ],
139// "experiments": [
140// {
141// "name": "Enabled",
142// "params": {
143// "x": "1"
144// },
145// "enable_features": [
146// "UnitTestEnabled"
147// ]
148// }
149// ]
150// }
151// ]
152// }
153
154const Study::Platform array_kFieldTrialConfig_platforms_0[] = {
155 Study::PLATFORM_ANDROID,
156 Study::PLATFORM_ANDROID_WEBLAYER,
157 Study::PLATFORM_ANDROID_WEBVIEW,
158 Study::PLATFORM_CHROMEOS,
159 Study::PLATFORM_CHROMEOS_LACROS,
160 Study::PLATFORM_FUCHSIA,
161 Study::PLATFORM_IOS,
162 Study::PLATFORM_LINUX,
163 Study::PLATFORM_MAC,
164 Study::PLATFORM_WINDOWS,
165};
166
167const char* enable_features_0[] = {"UnitTestEnabled"};
168const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params_0[] = {
169 {
170 "x",
171 "1",
172 },
173};
174
175const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
176 {/*name=*/"Enabled",
177 /*platforms=*/array_kFieldTrialConfig_platforms_0,
178 /*platforms_size=*/10,
179 /*form_factors=*/{},
180 /*form_factors_size=*/0,
Arthur Sonzogni14af2a92024-01-16 14:51:01181 /*is_low_end_device=*/std::nullopt,
Luc Nguyen1180c662022-02-08 20:38:59182 /*min_os_version=*/nullptr,
183 /*params=*/array_kFieldTrialConfig_params_0,
184 /*params_size=*/1,
185 /*enable_features=*/enable_features_0,
186 /*enable_features_size=*/1,
187 /*disable_features=*/nullptr,
188 /*disable_features_size=*/0,
189 /*forcing_flag=*/nullptr,
190 /*override_ui_string=*/nullptr,
191 /*override_ui_string_size=*/0},
192};
193
194const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
195 {/*name=*/"UnitTest",
196 /*experiments=*/array_kFieldTrialConfig_experiments_0,
197 /*experiments_size=*/1},
198};
199
Roger McFarlane3da6db2732021-10-06 13:41:04200} // namespace
201
202const SignedSeedData kTestSeedData{
203 kTestSeed_StudyNames, kTestSeed_Base64UncompressedData,
204 kTestSeed_Base64CompressedData, kTestSeed_Base64Signature};
205
206const SignedSeedData kCrashingSeedData{
207 kCrashingSeed_StudyNames, kCrashingSeed_Base64UncompressedData,
208 kCrashingSeed_Base64CompressedData, kCrashingSeed_Base64Signature};
209
210const SignedSeedPrefKeys kSafeSeedPrefKeys{prefs::kVariationsSafeCompressedSeed,
211 prefs::kVariationsSafeSeedSignature};
212
213const SignedSeedPrefKeys kRegularSeedPrefKeys{prefs::kVariationsCompressedSeed,
214 prefs::kVariationsSeedSignature};
215
216SignedSeedData::SignedSeedData(base::span<const char*> in_study_names,
217 const char* in_base64_uncompressed_data,
218 const char* in_base64_compressed_data,
219 const char* in_base64_signature)
220 : study_names(std::move(in_study_names)),
221 base64_uncompressed_data(in_base64_uncompressed_data),
222 base64_compressed_data(in_base64_compressed_data),
223 base64_signature(in_base64_signature) {}
224
225SignedSeedData::~SignedSeedData() = default;
226
227SignedSeedData::SignedSeedData(const SignedSeedData&) = default;
228SignedSeedData::SignedSeedData(SignedSeedData&&) = default;
229SignedSeedData& SignedSeedData::operator=(const SignedSeedData&) = default;
230SignedSeedData& SignedSeedData::operator=(SignedSeedData&&) = default;
Caitlin Fischerd7651aed2021-07-13 03:20:40231
Caitlin Fischer6920a082021-06-29 05:25:24232void DisableTestingConfig() {
233 base::CommandLine::ForCurrentProcess()->AppendSwitch(
234 switches::kDisableFieldTrialTestingConfig);
235}
236
Luc Nguyen1180c662022-02-08 20:38:59237void EnableTestingConfig() {
238 base::CommandLine::ForCurrentProcess()->AppendSwitch(
239 switches::kEnableFieldTrialTestingConfig);
240}
241
Karthika Paia264586a2020-10-27 23:32:01242bool ExtractVariationIds(const std::string& variations,
243 std::set<VariationID>* variation_ids,
244 std::set<VariationID>* trigger_ids) {
245 std::string serialized_proto;
246 if (!base::Base64Decode(variations, &serialized_proto))
247 return false;
248 ClientVariations proto;
249 if (!proto.ParseFromString(serialized_proto))
250 return false;
251 for (int i = 0; i < proto.variation_id_size(); ++i)
252 variation_ids->insert(proto.variation_id(i));
253 for (int i = 0; i < proto.trigger_variation_id_size(); ++i)
254 trigger_ids->insert(proto.trigger_variation_id(i));
255 return true;
256}
257
258scoped_refptr<base::FieldTrial> CreateTrialAndAssociateId(
259 const std::string& trial_name,
260 const std::string& default_group_name,
261 IDCollectionKey key,
262 VariationID id) {
263 AssociateGoogleVariationID(key, trial_name, default_group_name, id);
264 scoped_refptr<base::FieldTrial> trial(
265 base::FieldTrialList::CreateFieldTrial(trial_name, default_group_name));
266 DCHECK(trial);
267
268 if (trial) {
269 // Ensure the trial is registered under the correct key so we can look it
270 // up.
Steven Holtef1551602022-09-03 06:38:38271 trial->Activate();
Karthika Paia264586a2020-10-27 23:32:01272 }
273
274 return trial;
275}
276
Roger McFarlane3da6db2732021-10-06 13:41:04277void SimulateCrash(PrefService* local_state) {
278 local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false);
279 metrics::CleanExitBeacon::SkipCleanShutdownStepsForTesting();
280}
281
282void WriteSeedData(PrefService* local_state,
283 const SignedSeedData& seed_data,
284 const SignedSeedPrefKeys& pref_keys) {
285 local_state->SetString(pref_keys.base64_compressed_data_key,
286 seed_data.base64_compressed_data);
287 local_state->SetString(pref_keys.base64_signature_key,
288 seed_data.base64_signature);
289 local_state->CommitPendingWrite();
290}
291
292bool FieldTrialListHasAllStudiesFrom(const SignedSeedData& seed_data) {
293 return base::ranges::all_of(seed_data.study_names, [](const char* study) {
294 return base::FieldTrialList::TrialExists(study);
295 });
296}
297
Luc Nguyen1180c662022-02-08 20:38:59298void ResetVariations() {
299 testing::ClearAllVariationIDs();
300 testing::ClearAllVariationParams();
301}
302
303const FieldTrialTestingConfig kTestingConfig = {
304 array_kFieldTrialConfig_studies,
305 1,
306};
307
Steven Holtef08a3362022-09-15 07:33:06308std::unique_ptr<ClientFilterableState> CreateDummyClientFilterableState() {
309 auto client_state = std::make_unique<ClientFilterableState>(
James Lee0d5fd0d2023-02-24 10:28:31310 base::BindOnce([] { return false; }),
311 base::BindOnce([] { return base::flat_set<uint64_t>(); }));
Steven Holtef08a3362022-09-15 07:33:06312 client_state->locale = "en-CA";
313 client_state->reference_date = base::Time::Now();
314 client_state->version = base::Version("20.0.0.0");
315 client_state->channel = Study::STABLE;
316 client_state->form_factor = Study::PHONE;
317 client_state->platform = Study::PLATFORM_ANDROID;
318 return client_state;
319}
320
Yulun Zeng2e851f002024-01-30 19:06:32321// Constructs mocked EntropyProviders.
Steven Holtea84bc222022-09-29 07:11:46322MockEntropyProviders::MockEntropyProviders(
323 MockEntropyProviders::Results results,
Steven Holte896279f2022-10-21 20:32:30324 uint32_t low_entropy_domain)
Steven Holtea84bc222022-09-29 07:11:46325 : EntropyProviders(results.high_entropy.has_value() ? "client_id" : "",
Yulun Zeng2e851f002024-01-30 19:06:32326 {0, low_entropy_domain},
Yulun Zeng83cea9492024-03-12 18:26:03327 results.limited_entropy.has_value()
328 ? "limited_entropy_randomization_source"
329 : std::string_view()),
Steven Holtea84bc222022-09-29 07:11:46330 low_provider_(results.low_entropy),
Yulun Zeng83cea9492024-03-12 18:26:03331 high_provider_(results.high_entropy.value_or(0)),
332 limited_provider_(results.limited_entropy.value_or(0)) {}
Steven Holtea84bc222022-09-29 07:11:46333
334MockEntropyProviders::~MockEntropyProviders() = default;
335
336const base::FieldTrial::EntropyProvider& MockEntropyProviders::low_entropy()
337 const {
338 return low_provider_;
339}
340
341const base::FieldTrial::EntropyProvider& MockEntropyProviders::default_entropy()
342 const {
343 if (default_entropy_is_high_entropy()) {
344 return high_provider_;
345 }
346 return low_provider_;
347}
348
Yulun Zeng83cea9492024-03-12 18:26:03349const base::FieldTrial::EntropyProvider& MockEntropyProviders::limited_entropy()
350 const {
351 CHECK(has_limited_entropy());
352 return limited_provider_;
353}
354
Yulun Zeng29c77e5d2024-02-16 02:24:56355std::string GZipAndB64EncodeToHexString(const VariationsSeed& seed) {
356 auto serialized = seed.SerializeAsString();
357 std::string compressed;
358 compression::GzipCompress(serialized, &compressed);
359 return base::Base64Encode(compressed);
360}
361
362bool ContainsTrialName(const std::vector<ActiveGroupId>& active_group_ids,
363 std::string_view trial_name) {
364 auto hashed_name = HashName(trial_name);
365 for (const auto& trial : active_group_ids) {
366 if (trial.name == hashed_name) {
367 return true;
368 }
369 }
370 return false;
371}
372
Caitlin Fischer6920a082021-06-29 05:25:24373} // namespace variations