OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/common/variations/variations_util.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include "base/command_line.h" | |
13 #include "base/feature_list.h" | |
14 #include "base/metrics/field_trial.h" | |
15 #include "base/strings/string_split.h" | |
16 #include "base/strings/stringprintf.h" | |
17 #include "chrome/common/variations/fieldtrial_testing_config.h" | |
18 #include "components/variations/variations_associated_data.h" | |
19 #include "net/base/escape.h" | |
20 | |
21 namespace chrome_variations { | |
22 | |
23 namespace { | |
24 | |
25 std::string EscapeValue(const std::string& value) { | |
26 return net::UnescapeURLComponent( | |
27 value, net::UnescapeRule::PATH_SEPARATORS | | |
28 net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); | |
29 } | |
30 | |
31 void AssociateParamsFromExperiment( | |
32 const std::string& study_name, | |
33 const FieldTrialTestingExperiment& experiment, | |
34 base::FeatureList* feature_list) { | |
35 if (experiment.params_size != 0) { | |
36 std::map<std::string, std::string> params; | |
37 for (size_t i = 0; i < experiment.params_size; ++i) { | |
38 const FieldTrialTestingExperimentParams& param = experiment.params[i]; | |
39 params[param.key] = param.value; | |
40 } | |
41 variations::AssociateVariationParams(study_name, experiment.name, params); | |
42 } | |
43 base::FieldTrial* trial = | |
44 base::FieldTrialList::CreateFieldTrial(study_name, experiment.name); | |
45 | |
46 if (!trial) { | |
47 DLOG(WARNING) << "Field trial config study skipped: " << study_name | |
48 << "." << experiment.name | |
49 << " (it is overridden from chrome://flags)"; | |
50 return; | |
51 } | |
52 | |
53 for (size_t i = 0; i < experiment.enable_features_size; ++i) { | |
54 feature_list->RegisterFieldTrialOverride( | |
55 experiment.enable_features[i], | |
56 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial); | |
57 } | |
58 for (size_t i = 0; i < experiment.disable_features_size; ++i) { | |
59 feature_list->RegisterFieldTrialOverride( | |
60 experiment.disable_features[i], | |
61 base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial); | |
62 } | |
63 } | |
64 | |
65 // Chooses an experiment taking into account the command line. Defaults to | |
66 // picking the first experiment. | |
67 const FieldTrialTestingExperiment& ChooseExperiment( | |
68 const FieldTrialTestingExperiment experiments[], | |
69 size_t experiment_size) { | |
70 DCHECK_GT(experiment_size, 0ul); | |
71 const auto& command_line = *base::CommandLine::ForCurrentProcess(); | |
72 size_t chosen_index = 0; | |
73 for (size_t i = 1; i < experiment_size && chosen_index == 0; ++i) { | |
74 const auto& experiment = experiments[i]; | |
75 if (experiment.forcing_flag && | |
76 command_line.HasSwitch(experiment.forcing_flag)) { | |
77 chosen_index = i; | |
78 break; | |
79 } | |
80 } | |
81 DCHECK_GT(experiment_size, chosen_index); | |
82 return experiments[chosen_index]; | |
83 } | |
84 | |
85 } // namespace | |
86 | |
87 bool AssociateParamsFromString(const std::string& varations_string) { | |
88 // Format: Trial1.Group1:k1/v1/k2/v2,Trial2.Group2:k1/v1/k2/v2 | |
89 std::set<std::pair<std::string, std::string>> trial_groups; | |
90 for (const base::StringPiece& experiment_group : base::SplitStringPiece( | |
91 varations_string, ",", | |
92 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { | |
93 std::vector<base::StringPiece> experiment = base::SplitStringPiece( | |
94 experiment_group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
95 if (experiment.size() != 2) { | |
96 DLOG(ERROR) << "Experiment and params should be separated by ':'"; | |
97 return false; | |
98 } | |
99 | |
100 std::vector<std::string> group_parts = base::SplitString( | |
101 experiment[0], ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
102 if (group_parts.size() != 2) { | |
103 DLOG(ERROR) << "Trial and group name should be separated by '.'"; | |
104 return false; | |
105 } | |
106 | |
107 std::vector<std::string> key_values = base::SplitString( | |
108 experiment[1], "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
109 if (key_values.size() % 2 != 0) { | |
110 DLOG(ERROR) << "Param name and param value should be separated by '/'"; | |
111 return false; | |
112 } | |
113 std::string trial = EscapeValue(group_parts[0]); | |
114 std::string group = EscapeValue(group_parts[1]); | |
115 auto trial_group = std::make_pair(trial, group); | |
116 if (trial_groups.find(trial_group) != trial_groups.end()) { | |
117 DLOG(ERROR) << base::StringPrintf( | |
118 "A (trial, group) pair listed more than once. (%s, %s)", | |
119 trial.c_str(), group.c_str()); | |
120 return false; | |
121 } | |
122 trial_groups.insert(trial_group); | |
123 std::map<std::string, std::string> params; | |
124 for (size_t i = 0; i < key_values.size(); i += 2) { | |
125 std::string key = EscapeValue(key_values[i]); | |
126 std::string value = EscapeValue(key_values[i + 1]); | |
127 params[key] = value; | |
128 } | |
129 variations::AssociateVariationParams(trial, group, params); | |
130 } | |
131 return true; | |
132 } | |
133 | |
134 void AssociateParamsFromFieldTrialConfig(const FieldTrialTestingConfig& config, | |
135 base::FeatureList* feature_list) { | |
136 for (size_t i = 0; i < config.studies_size; ++i) { | |
137 const FieldTrialTestingStudy& study = config.studies[i]; | |
138 if (study.experiments_size > 0) { | |
139 AssociateParamsFromExperiment( | |
140 study.name, | |
141 ChooseExperiment(study.experiments, study.experiments_size), | |
142 feature_list); | |
143 } else { | |
144 DLOG(ERROR) << "Unexpected empty study: " << study.name; | |
145 } | |
146 } | |
147 } | |
148 | |
149 void AssociateDefaultFieldTrialConfig(base::FeatureList* feature_list) { | |
150 AssociateParamsFromFieldTrialConfig(kFieldTrialConfig, feature_list); | |
151 } | |
152 | |
153 } // namespace chrome_variations | |
OLD | NEW |