// Copyright 2020 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 "components/variations/variations_test_utils.h" #include "base/base64.h" #include "base/command_line.h" #include "base/feature_list.h" #include "components/metrics/clean_exit_beacon.h" #include "components/metrics/metrics_pref_names.h" #include "components/prefs/pref_service.h" #include "components/variations/field_trial_config/fieldtrial_testing_config.h" #include "components/variations/pref_names.h" #include "components/variations/proto/client_variations.pb.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_switches.h" #include "third_party/zlib/google/compression_utils.h" namespace variations { namespace { const char* kTestSeed_StudyNames[] = {"UMA-Uniformity-Trial-10-Percent"}; const char kTestSeed_Base64UncompressedData[] = "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5pZm" "9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBABSgwK" "CGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0EAFKDA" "oIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBfMDgQAUoM" "Cghncm91cF8wORAB"; const char kTestSeed_Base64CompressedData[] = "H4sIAAAAAAAAAOPSMEwxsjQxM0lLMk4xt0hLMzQ1NUs1TTI1NUw2MzExT05KNjdJNU1LMRDay8" "glH+rrqBual5mWX5SbWVKpG1KUmZija2igG5BalJyaVyLRMGfSUlYLRif2lNS0xNKcEi9uLhhT" "gNGLh4sjvSi/tCDewBCFZ4TCM0bhmaDwTFF4Zig8cxSeBQrPUoARAEVeJPrqAAAA"; const char kTestSeed_Base64Signature[] = "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy96" "JkMYgzTkHPwbv7K/CmgA=="; const char* kCrashingSeed_StudyNames[] = {"CrashingStudy"}; const char kCrashingSeed_Base64UncompressedData[] = "CigzNWVkMmQ5ZTM1NGI0MTRiZWZkZjkzMGE3MzQwOTQwMTljMDE2MmYxEp4CCg1DcmFzaGluZ1" "N0dWR5OAFKOAoNRW5hYmxlZExhdW5jaBBkYiUKI0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hG" "b3JUZXN0aW5nSlcKLEZvcmNlZE9uX0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hGb3JUZXN0aW" "5nEABiJRojRm9yY2VGaWVsZFRyaWFsU2V0dXBDcmFzaEZvclRlc3RpbmdKWAotRm9yY2VkT2Zm" "X0ZvcmNlRmllbGRUcmlhbFNldHVwQ3Jhc2hGb3JUZXN0aW5nEABiJSIjRm9yY2VGaWVsZFRyaW" "FsU2V0dXBDcmFzaEZvclRlc3RpbmdSHhIEOTEuKiAAIAEgAiADKAQoBSgGKAAoASgCKAMoCSIt" "aGFzaC80YWE1NmExZGMzMGRmYzc2NzYxNTI0OGQ2ZmVlMjk4MzAxOThiMjc2"; const char kCrashingSeed_Base64CompressedData[] = "H4sIAAAAAAAAAI3QwUvDMBTH8babwgKDsaMHKZNBEKdJk6bJWbbDEAQ30JskeS+2UKp07cF/" "Zn+rZfgH9Py+73P4ESpyhAwMilw6yaXDAMEIZgshmZGMG8+4ygJfnhMyf27tqayar0PXw6+" "O95rMt411NcKL7RtfLsCtyd3uu/W4q7CGY1vZ+oBd/" "3P5HA5HPHUDsH8nD5cMXpvPEf0icuubUfAH2fzDIYyVV2Pkt9vl1PDH+zRK4zRJJ3RKr+" "g1jWhMEzqhs9WmHPonaW2uLAcvGARfqELxPJMaVEDMjBbDotplhfoDs9NLbnoBAAA="; const char kCrashingSeed_Base64Signature[] = "MEQCIEn1+VsBfNA93dxzpk+BLhdO91kMQnofxfTK5Uo8vDi8AiAnTCFCIPgEGWNOKzuKfNWn6" "emB6pnGWjSTbI/pvfxHnw=="; // Create mock testing config equivalent to: // { // "UnitTest": [ // { // "platforms": [ // "android", // "android_weblayer", // "android_webview", // "chromeos", // "chromeos_lacros", // "fuchsia", // "ios", // "linux", // "mac", // "windows" // ], // "experiments": [ // { // "name": "Enabled", // "params": { // "x": "1" // }, // "enable_features": [ // "UnitTestEnabled" // ] // } // ] // } // ] // } const Study::Platform array_kFieldTrialConfig_platforms_0[] = { Study::PLATFORM_ANDROID, Study::PLATFORM_ANDROID_WEBLAYER, Study::PLATFORM_ANDROID_WEBVIEW, Study::PLATFORM_CHROMEOS, Study::PLATFORM_CHROMEOS_LACROS, Study::PLATFORM_FUCHSIA, Study::PLATFORM_IOS, Study::PLATFORM_LINUX, Study::PLATFORM_MAC, Study::PLATFORM_WINDOWS, }; const char* enable_features_0[] = {"UnitTestEnabled"}; const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params_0[] = { { "x", "1", }, }; const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = { {/*name=*/"Enabled", /*platforms=*/array_kFieldTrialConfig_platforms_0, /*platforms_size=*/10, /*form_factors=*/{}, /*form_factors_size=*/0, /*is_low_end_device=*/absl::nullopt, /*min_os_version=*/nullptr, /*params=*/array_kFieldTrialConfig_params_0, /*params_size=*/1, /*enable_features=*/enable_features_0, /*enable_features_size=*/1, /*disable_features=*/nullptr, /*disable_features_size=*/0, /*forcing_flag=*/nullptr, /*override_ui_string=*/nullptr, /*override_ui_string_size=*/0}, }; const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = { {/*name=*/"UnitTest", /*experiments=*/array_kFieldTrialConfig_experiments_0, /*experiments_size=*/1}, }; } // namespace const SignedSeedData kTestSeedData{ kTestSeed_StudyNames, kTestSeed_Base64UncompressedData, kTestSeed_Base64CompressedData, kTestSeed_Base64Signature}; const SignedSeedData kCrashingSeedData{ kCrashingSeed_StudyNames, kCrashingSeed_Base64UncompressedData, kCrashingSeed_Base64CompressedData, kCrashingSeed_Base64Signature}; const SignedSeedPrefKeys kSafeSeedPrefKeys{prefs::kVariationsSafeCompressedSeed, prefs::kVariationsSafeSeedSignature}; const SignedSeedPrefKeys kRegularSeedPrefKeys{prefs::kVariationsCompressedSeed, prefs::kVariationsSeedSignature}; SignedSeedData::SignedSeedData(base::span in_study_names, const char* in_base64_uncompressed_data, const char* in_base64_compressed_data, const char* in_base64_signature) : study_names(std::move(in_study_names)), base64_uncompressed_data(in_base64_uncompressed_data), base64_compressed_data(in_base64_compressed_data), base64_signature(in_base64_signature) {} SignedSeedData::~SignedSeedData() = default; SignedSeedData::SignedSeedData(const SignedSeedData&) = default; SignedSeedData::SignedSeedData(SignedSeedData&&) = default; SignedSeedData& SignedSeedData::operator=(const SignedSeedData&) = default; SignedSeedData& SignedSeedData::operator=(SignedSeedData&&) = default; void DisableTestingConfig() { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kDisableFieldTrialTestingConfig); } void EnableTestingConfig() { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableFieldTrialTestingConfig); } bool ExtractVariationIds(const std::string& variations, std::set* variation_ids, std::set* trigger_ids) { std::string serialized_proto; if (!base::Base64Decode(variations, &serialized_proto)) return false; ClientVariations proto; if (!proto.ParseFromString(serialized_proto)) return false; for (int i = 0; i < proto.variation_id_size(); ++i) variation_ids->insert(proto.variation_id(i)); for (int i = 0; i < proto.trigger_variation_id_size(); ++i) trigger_ids->insert(proto.trigger_variation_id(i)); return true; } scoped_refptr CreateTrialAndAssociateId( const std::string& trial_name, const std::string& default_group_name, IDCollectionKey key, VariationID id) { AssociateGoogleVariationID(key, trial_name, default_group_name, id); scoped_refptr trial( base::FieldTrialList::CreateFieldTrial(trial_name, default_group_name)); DCHECK(trial); if (trial) { // Ensure the trial is registered under the correct key so we can look it // up. trial->group(); } return trial; } void SimulateCrash(PrefService* local_state) { local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false); metrics::CleanExitBeacon::SkipCleanShutdownStepsForTesting(); } void WriteSeedData(PrefService* local_state, const SignedSeedData& seed_data, const SignedSeedPrefKeys& pref_keys) { local_state->SetString(pref_keys.base64_compressed_data_key, seed_data.base64_compressed_data); local_state->SetString(pref_keys.base64_signature_key, seed_data.base64_signature); local_state->CommitPendingWrite(); } bool FieldTrialListHasAllStudiesFrom(const SignedSeedData& seed_data) { return base::ranges::all_of(seed_data.study_names, [](const char* study) { return base::FieldTrialList::TrialExists(study); }); } void ResetVariations() { testing::ClearAllVariationIDs(); testing::ClearAllVariationParams(); } const FieldTrialTestingConfig kTestingConfig = { array_kFieldTrialConfig_studies, 1, }; } // namespace variations