1 // Copyright 2017 The Chromium Authors
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 "base/test/scoped_feature_list.h"
6
7 #include <map>
8 #include <string>
9 #include <utility>
10
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/field_trial_params.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16 namespace test {
17
18 namespace {
19
20 BASE_FEATURE(kTestFeature1, "TestFeature1", FEATURE_DISABLED_BY_DEFAULT);
21 BASE_FEATURE(kTestFeature2, "TestFeature2", FEATURE_DISABLED_BY_DEFAULT);
22
ExpectFeatures(const std::string & enabled_features,const std::string & disabled_features)23 void ExpectFeatures(const std::string& enabled_features,
24 const std::string& disabled_features) {
25 FeatureList* list = FeatureList::GetInstance();
26 std::string actual_enabled_features;
27 std::string actual_disabled_features;
28
29 list->GetFeatureOverrides(&actual_enabled_features,
30 &actual_disabled_features);
31
32 EXPECT_EQ(enabled_features, actual_enabled_features);
33 EXPECT_EQ(disabled_features, actual_disabled_features);
34 }
35
GetActiveFieldTrialGroupName(const std::string trial_name)36 std::string GetActiveFieldTrialGroupName(const std::string trial_name) {
37 FieldTrial::ActiveGroups groups;
38 FieldTrialList::GetActiveFieldTrialGroups(&groups);
39 for (const auto& group : groups) {
40 if (group.trial_name == trial_name)
41 return group.group_name;
42 }
43 return std::string();
44 }
45
46 } // namespace
47
48 class ScopedFeatureListTest : public testing::Test {
49 public:
ScopedFeatureListTest()50 ScopedFeatureListTest() {
51 // Clear default feature list.
52 std::unique_ptr<FeatureList> feature_list(new FeatureList);
53 feature_list->InitializeFromCommandLine(std::string(), std::string());
54 original_feature_list_ = FeatureList::ClearInstanceForTesting();
55 FeatureList::SetInstance(std::move(feature_list));
56 }
57
58 ScopedFeatureListTest(const ScopedFeatureListTest&) = delete;
59 ScopedFeatureListTest& operator=(const ScopedFeatureListTest&) = delete;
60
~ScopedFeatureListTest()61 ~ScopedFeatureListTest() override {
62 // Restore feature list.
63 if (original_feature_list_) {
64 FeatureList::ClearInstanceForTesting();
65 FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_));
66 }
67 }
68
69 private:
70 // Save the present FeatureList and restore it after test finish.
71 std::unique_ptr<FeatureList> original_feature_list_;
72 };
73
TEST_F(ScopedFeatureListTest,BasicScoped)74 TEST_F(ScopedFeatureListTest, BasicScoped) {
75 ExpectFeatures(std::string(), std::string());
76 EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
77 {
78 test::ScopedFeatureList feature_list1;
79 feature_list1.InitFromCommandLine("TestFeature1", std::string());
80 ExpectFeatures("TestFeature1", std::string());
81 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
82 }
83 ExpectFeatures(std::string(), std::string());
84 EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
85 }
86
TEST_F(ScopedFeatureListTest,InitFromCommandLineWithFeatureParams)87 TEST_F(ScopedFeatureListTest, InitFromCommandLineWithFeatureParams) {
88 const std::map<std::string, std::string> feature_params1 = {{"x", "uma"},
89 {"y", "ukm"}};
90 const std::map<std::string, std::string> feature_params2 = {{"x", "ukm"},
91 {"y", "uma"}};
92
93 test::ScopedFeatureList feature_list1;
94 feature_list1.InitFromCommandLine("TestFeature1<foo.bar:x/uma/y/ukm", "");
95
96 // Check initial state. Field trial and parameters should be set correctly.
97 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
98 FieldTrial::ActiveGroups active_groups;
99 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
100 EXPECT_EQ(1u, active_groups.size());
101 FieldTrial* original_field_trial =
102 FieldTrialList::Find(active_groups[0].trial_name);
103 std::map<std::string, std::string> actualParams;
104 EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
105 EXPECT_EQ(feature_params1, actualParams);
106
107 {
108 // Override feature with existing field trial.
109 test::ScopedFeatureList feature_list2;
110
111 feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1,
112 feature_params2);
113 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
114 EXPECT_NE(original_field_trial, FeatureList::GetFieldTrial(kTestFeature1));
115 actualParams.clear();
116 EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
117 EXPECT_EQ(feature_params2, actualParams);
118 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
119 }
120
121 // Check that initial state is restored.
122 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
123 active_groups.clear();
124 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
125 EXPECT_EQ(1u, active_groups.size());
126 EXPECT_EQ(original_field_trial, FeatureList::GetFieldTrial(kTestFeature1));
127 actualParams.clear();
128 EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
129 EXPECT_EQ(feature_params1, actualParams);
130 }
131
TEST_F(ScopedFeatureListTest,EnableWithFeatureParameters)132 TEST_F(ScopedFeatureListTest, EnableWithFeatureParameters) {
133 const char kParam1[] = "param_1";
134 const char kParam2[] = "param_2";
135 const char kValue1[] = "value_1";
136 const char kValue2[] = "value_2";
137 std::map<std::string, std::string> parameters;
138 parameters[kParam1] = kValue1;
139 parameters[kParam2] = kValue2;
140
141 ExpectFeatures(std::string(), std::string());
142 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
143 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
144 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
145 FieldTrial::ActiveGroups active_groups;
146 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
147 EXPECT_EQ(0u, active_groups.size());
148
149 {
150 test::ScopedFeatureList feature_list;
151
152 feature_list.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
153 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
154 EXPECT_EQ(kValue1,
155 GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
156 EXPECT_EQ(kValue2,
157 GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
158 active_groups.clear();
159 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
160 EXPECT_EQ(1u, active_groups.size());
161 }
162
163 ExpectFeatures(std::string(), std::string());
164 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
165 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
166 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
167 active_groups.clear();
168 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
169 EXPECT_EQ(0u, active_groups.size());
170 }
171
TEST_F(ScopedFeatureListTest,OverrideWithFeatureParameters)172 TEST_F(ScopedFeatureListTest, OverrideWithFeatureParameters) {
173 scoped_refptr<FieldTrial> trial =
174 FieldTrialList::CreateFieldTrial("foo", "bar");
175 const char kParam[] = "param_1";
176 const char kValue[] = "value_1";
177 const char kValue0[] = "value_0";
178 std::map<std::string, std::string> parameters;
179 parameters[kParam] = kValue;
180
181 test::ScopedFeatureList feature_list1;
182 feature_list1.InitFromCommandLine(
183 "TestFeature1<foo.bar:param_1/value_0,TestFeature2", std::string());
184
185 // Check initial state.
186 ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
187 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
188 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
189 // ScopedFeatureList always scope features, field trials and their associated
190 // parameters. So ScopedFeatureList::InitFromCommandLine() creates another
191 // FieldTrial instance whose trial name, group name and associated parameters
192 // are the same as |trial|, and changes |kTestFeature1|'s field trial to
193 // be the newly created one.
194 EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
195 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
196 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
197 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
198 EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo"));
199
200 FieldTrial* trial_for_test_feature1 =
201 FeatureList::GetFieldTrial(kTestFeature1);
202 EXPECT_EQ("foo", trial_for_test_feature1->trial_name());
203 EXPECT_EQ("bar", trial_for_test_feature1->group_name());
204
205 {
206 // Override feature with existing field trial.
207 test::ScopedFeatureList feature_list2;
208
209 feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
210 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
211 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
212 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
213 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
214 EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
215 EXPECT_NE(trial_for_test_feature1,
216 FeatureList::GetFieldTrial(kTestFeature1));
217 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
218 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
219 }
220
221 {
222 // Override feature with existing field trial.
223 test::ScopedFeatureList feature_list2;
224
225 feature_list2.InitFromCommandLine("TestFeature1<foo.bar2:param_1/value_1",
226 std::string());
227 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
228 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
229 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
230 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
231 EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
232 EXPECT_NE(trial_for_test_feature1,
233 FeatureList::GetFieldTrial(kTestFeature1));
234 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
235 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
236
237 // foo's active group is now bar2, not bar.
238 EXPECT_TRUE(FieldTrialList::IsTrialActive("foo"));
239 EXPECT_EQ("bar2", GetActiveFieldTrialGroupName("foo"));
240 }
241
242 // Check that initial state is restored.
243 ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
244 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
245 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
246 EXPECT_EQ(trial_for_test_feature1, FeatureList::GetFieldTrial(kTestFeature1));
247 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
248 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
249 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
250 // foo's active group is bar, because initial state is restored.
251 EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo"));
252
253 {
254 // Override feature with no existing field trial.
255 test::ScopedFeatureList feature_list2;
256
257 feature_list2.InitAndEnableFeatureWithParameters(kTestFeature2, parameters);
258 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
259 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
260 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
261 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
262 EXPECT_EQ(trial_for_test_feature1->trial_name(),
263 FeatureList::GetFieldTrial(kTestFeature1)->trial_name());
264 EXPECT_EQ(trial_for_test_feature1->group_name(),
265 FeatureList::GetFieldTrial(kTestFeature1)->group_name());
266 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
267 }
268
269 // Check that initial state is restored.
270 ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
271 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
272 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
273 EXPECT_EQ(trial_for_test_feature1, FeatureList::GetFieldTrial(kTestFeature1));
274 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
275 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
276 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
277 }
278
TEST_F(ScopedFeatureListTest,OverrideWithFeatureMultipleParameters)279 TEST_F(ScopedFeatureListTest, OverrideWithFeatureMultipleParameters) {
280 const char kParam1[] = "param_1";
281 const char kValue1[] = "value_1";
282 const char kParam2[] = "param_2";
283 const char kValue2[] = "value_2";
284 const char kValue3[] = "value_3";
285 std::map<std::string, std::string> parameters;
286 parameters[kParam1] = kValue3;
287
288 test::ScopedFeatureList feature_list1;
289 feature_list1.InitFromCommandLine(
290 "TestFeature1<foo.bar:param_1/value_1/param_2/"
291 "value_2,TestFeature2:param_1/value_2",
292 std::string());
293
294 // Check initial state.
295 ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2",
296 std::string());
297 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
298 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
299 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
300 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
301 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
302 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
303 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1));
304 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2));
305
306 FieldTrial* trial = FieldTrialList::Find("foo");
307 EXPECT_EQ("bar", trial->GetGroupNameWithoutActivation());
308 EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo"));
309
310 FieldTrial* trial2 = FieldTrialList::Find("StudyTestFeature2");
311 EXPECT_EQ("GroupTestFeature2", trial2->GetGroupNameWithoutActivation());
312 EXPECT_EQ("GroupTestFeature2",
313 GetActiveFieldTrialGroupName("StudyTestFeature2"));
314
315 {
316 // Override feature with existing field trial.
317 test::ScopedFeatureList feature_list2;
318
319 feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
320 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
321 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
322 EXPECT_EQ(kValue3,
323 GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
324 // param_2 is not set.
325 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
326 EXPECT_EQ(kValue2,
327 GetFieldTrialParamValueByFeature(kTestFeature2, kParam1));
328 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2));
329 EXPECT_NE(trial, FeatureList::GetFieldTrial(kTestFeature1));
330 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
331 EXPECT_NE(trial2, FeatureList::GetFieldTrial(kTestFeature2));
332 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
333 }
334
335 // Check that initial state is restored.
336 ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2",
337 std::string());
338 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
339 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
340 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1));
341 EXPECT_EQ(trial2, FeatureList::GetFieldTrial(kTestFeature2));
342 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
343 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
344 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1));
345 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2));
346 // foo's active group is bar, because initial state is restored.
347 EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo"));
348 EXPECT_EQ("GroupTestFeature2",
349 GetActiveFieldTrialGroupName("StudyTestFeature2"));
350
351 {
352 // Override feature with existing field trial.
353 test::ScopedFeatureList feature_list2;
354
355 feature_list2.InitFromCommandLine("TestFeature1<foo.bar2:param_2/value_3",
356 std::string());
357 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
358 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
359 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
360 EXPECT_EQ(kValue3,
361 GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
362 EXPECT_EQ(kValue2,
363 GetFieldTrialParamValueByFeature(kTestFeature2, kParam1));
364 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2));
365 EXPECT_NE(trial, FeatureList::GetFieldTrial(kTestFeature1));
366 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
367 EXPECT_EQ("foo", FeatureList::GetFieldTrial(kTestFeature1)->trial_name());
368 EXPECT_EQ("bar2", FeatureList::GetFieldTrial(kTestFeature1)->group_name());
369 EXPECT_NE(trial2, FeatureList::GetFieldTrial(kTestFeature2));
370 EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
371
372 // foo's active group is now bar2, not bar.
373 EXPECT_TRUE(FieldTrialList::IsTrialActive("foo"));
374 EXPECT_EQ("bar2", GetActiveFieldTrialGroupName("foo"));
375 }
376
377 // Check that initial state is restored.
378 ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2",
379 std::string());
380 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
381 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
382 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1));
383 EXPECT_EQ(trial2, FeatureList::GetFieldTrial(kTestFeature2));
384 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
385 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
386 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1));
387 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2));
388 EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo"));
389 }
390
TEST_F(ScopedFeatureListTest,OverrideMultipleFeaturesWithParameters)391 TEST_F(ScopedFeatureListTest, OverrideMultipleFeaturesWithParameters) {
392 scoped_refptr<FieldTrial> trial1 =
393 FieldTrialList::CreateFieldTrial("foo1", "bar1");
394 const char kParam[] = "param_1";
395 const char kValue0[] = "value_0";
396 const char kValue1[] = "value_1";
397 const char kValue2[] = "value_2";
398 std::map<std::string, std::string> parameters1;
399 parameters1[kParam] = kValue1;
400 std::map<std::string, std::string> parameters2;
401 parameters2[kParam] = kValue2;
402
403 test::ScopedFeatureList feature_list1;
404 feature_list1.InitFromCommandLine(
405 "TestFeature1<foo1:param_1/value_0,TestFeature2", std::string());
406
407 // Check initial state.
408 ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
409 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
410 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
411 EXPECT_EQ("foo1", FeatureList::GetFieldTrial(kTestFeature1)->trial_name());
412 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
413 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
414 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
415
416 // InitFromCommandLine() scopes field trials.
417 FieldTrial* trial = FieldTrialList::Find("foo1");
418 // --enable-features will create a group whose name is "Group" + feature
419 // name if no group name is specified. In this case, the feature name is
420 // "TestFeature1". So the group name is "GroupTestFeature1".
421 EXPECT_EQ("GroupTestFeature1", trial->GetGroupNameWithoutActivation());
422 EXPECT_NE(trial1.get(), trial);
423 // Because of "scoped", "bar1" disappears. Instead, "GroupTestFeature1"
424 // is created and activated.
425 EXPECT_NE("bar1", GetActiveFieldTrialGroupName("foo1"));
426 EXPECT_EQ("GroupTestFeature1", GetActiveFieldTrialGroupName("foo1"));
427
428 {
429 // Override multiple features with parameters.
430 test::ScopedFeatureList feature_list2;
431 feature_list2.InitWithFeaturesAndParameters(
432 {{kTestFeature1, parameters1}, {kTestFeature2, parameters2}}, {});
433
434 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
435 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
436 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
437 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
438 }
439
440 {
441 // Override a feature with a parameter and disable another one.
442 test::ScopedFeatureList feature_list2;
443 feature_list2.InitWithFeaturesAndParameters({{kTestFeature1, parameters2}},
444 {kTestFeature2});
445
446 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
447 EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
448 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
449 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
450 }
451
452 // Check that initial state is restored.
453 ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
454 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
455 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
456 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1));
457 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
458 EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
459 EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
460 }
461
TEST_F(ScopedFeatureListTest,ParamsWithSpecialCharsPreserved)462 TEST_F(ScopedFeatureListTest, ParamsWithSpecialCharsPreserved) {
463 // Check that special characters in param names and values are preserved.
464 const char kParam[] = ";_\\<:>/_!?";
465 const char kValue[] = ",;:/'!?";
466 FieldTrialParams params0 = {{kParam, kValue}};
467
468 test::ScopedFeatureList feature_list0;
469 feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params0}}, {});
470 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
471
472 {
473 const char kValue1[] = "normal";
474 FieldTrialParams params1 = {{kParam, kValue1}};
475 test::ScopedFeatureList feature_list1;
476 feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {});
477
478 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
479 }
480 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
481
482 {
483 const char kValue2[] = "[<(2)>]";
484 FieldTrialParams params2 = {{kParam, kValue2}};
485 test::ScopedFeatureList feature_list2;
486 feature_list2.InitWithFeaturesAndParameters({{kTestFeature2, params2}}, {});
487
488 EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
489 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
490 }
491 EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
492 }
493
TEST_F(ScopedFeatureListTest,ParamsWithEmptyValue)494 TEST_F(ScopedFeatureListTest, ParamsWithEmptyValue) {
495 const char kParam[] = "p";
496 const char kEmptyValue[] = "";
497 FieldTrialParams params = {{kParam, kEmptyValue}};
498
499 test::ScopedFeatureList feature_list0;
500 feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params}}, {});
501 EXPECT_EQ(kEmptyValue,
502 GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
503 {
504 const char kValue1[] = "normal";
505 FieldTrialParams params1 = {{kParam, kValue1}};
506 test::ScopedFeatureList feature_list1;
507 feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {});
508
509 EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
510 }
511 EXPECT_EQ(kEmptyValue,
512 GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
513 }
514
TEST_F(ScopedFeatureListTest,EnableFeatureOverrideDisable)515 TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) {
516 test::ScopedFeatureList feature_list1;
517 feature_list1.InitWithFeatures({}, {kTestFeature1});
518
519 {
520 test::ScopedFeatureList feature_list2;
521 feature_list2.InitWithFeatures({kTestFeature1}, {});
522 ExpectFeatures("TestFeature1", std::string());
523 }
524 }
525
TEST_F(ScopedFeatureListTest,FeatureOverrideNotMakeDuplicate)526 TEST_F(ScopedFeatureListTest, FeatureOverrideNotMakeDuplicate) {
527 test::ScopedFeatureList feature_list1;
528 feature_list1.InitWithFeatures({}, {kTestFeature1});
529
530 {
531 test::ScopedFeatureList feature_list2;
532 feature_list2.InitWithFeatures({}, {kTestFeature1});
533 ExpectFeatures(std::string(), "TestFeature1");
534 }
535 }
536
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDefault)537 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault) {
538 test::ScopedFeatureList feature_list1;
539 feature_list1.InitFromCommandLine("*TestFeature1", std::string());
540
541 {
542 test::ScopedFeatureList feature_list2;
543 feature_list2.InitWithFeatures({kTestFeature1}, {});
544 ExpectFeatures("TestFeature1", std::string());
545 }
546 }
547
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDefault2)548 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault2) {
549 test::ScopedFeatureList feature_list1;
550 feature_list1.InitFromCommandLine("*TestFeature1", std::string());
551
552 {
553 test::ScopedFeatureList feature_list2;
554 feature_list2.InitWithFeatures({}, {kTestFeature1});
555 ExpectFeatures(std::string(), "TestFeature1");
556 }
557 }
558
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithEnabledFieldTrial)559 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithEnabledFieldTrial) {
560 test::ScopedFeatureList feature_list1;
561
562 std::unique_ptr<FeatureList> feature_list(new FeatureList);
563 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
564 feature_list->RegisterFieldTrialOverride(
565 kTestFeature1.name, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
566 feature_list1.InitWithFeatureList(std::move(feature_list));
567
568 {
569 test::ScopedFeatureList feature_list2;
570 feature_list2.InitWithFeatures({kTestFeature1}, {});
571 ExpectFeatures("TestFeature1", std::string());
572 }
573 }
574
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDisabledFieldTrial)575 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDisabledFieldTrial) {
576 test::ScopedFeatureList feature_list1;
577
578 std::unique_ptr<FeatureList> feature_list(new FeatureList);
579 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
580 feature_list->RegisterFieldTrialOverride(
581 kTestFeature1.name, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
582 feature_list1.InitWithFeatureList(std::move(feature_list));
583
584 {
585 test::ScopedFeatureList feature_list2;
586 feature_list2.InitWithFeatures({kTestFeature1}, {});
587 ExpectFeatures("TestFeature1", std::string());
588 }
589 }
590
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingFeature)591 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature) {
592 test::ScopedFeatureList feature_list1;
593 feature_list1.InitWithFeatures({}, {kTestFeature1});
594
595 {
596 test::ScopedFeatureList feature_list2;
597 feature_list2.InitWithFeatures({}, {kTestFeature2});
598 EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
599 EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
600 }
601 }
602
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingFeature2)603 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature2) {
604 test::ScopedFeatureList feature_list1;
605 feature_list1.InitWithFeatures({}, {kTestFeature1});
606
607 {
608 test::ScopedFeatureList feature_list2;
609 feature_list2.InitWithFeatures({kTestFeature2}, {});
610 ExpectFeatures("TestFeature2", "TestFeature1");
611 }
612 }
613
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingDefaultFeature)614 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingDefaultFeature) {
615 test::ScopedFeatureList feature_list1;
616 feature_list1.InitFromCommandLine("*TestFeature1", std::string());
617
618 {
619 test::ScopedFeatureList feature_list2;
620 feature_list2.InitWithFeatures({}, {kTestFeature2});
621 ExpectFeatures("*TestFeature1", "TestFeature2");
622 }
623 }
624
TEST_F(ScopedFeatureListTest,ScopedFeatureListIsNoopWhenNotInitialized)625 TEST_F(ScopedFeatureListTest, ScopedFeatureListIsNoopWhenNotInitialized) {
626 test::ScopedFeatureList feature_list1;
627 feature_list1.InitFromCommandLine("*TestFeature1", std::string());
628
629 // A ScopedFeatureList on which Init() is not called should not reset things
630 // when going out of scope.
631 { test::ScopedFeatureList feature_list2; }
632
633 ExpectFeatures("*TestFeature1", std::string());
634 }
635
TEST_F(ScopedFeatureListTest,RestoreFieldTrialParamsCorrectlyWhenLeakedFieldTrialCreated)636 TEST_F(ScopedFeatureListTest,
637 RestoreFieldTrialParamsCorrectlyWhenLeakedFieldTrialCreated) {
638 test::ScopedFeatureList feature_list1;
639 feature_list1.InitFromCommandLine("TestFeature1:TestParam/TestValue1", "");
640 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
641 EXPECT_EQ("TestValue1",
642 GetFieldTrialParamValueByFeature(kTestFeature1, "TestParam"));
643
644 // content::InitializeFieldTrialAndFeatureList() creates a leaked
645 // FieldTrialList. To emulate the leaked one, declare
646 // unique_ptr<FieldTriaList> here and initialize it inside the following
647 // child scope.
648 std::unique_ptr<FieldTrialList> leaked_field_trial_list;
649 {
650 test::ScopedFeatureList feature_list2;
651 feature_list2.InitWithNullFeatureAndFieldTrialLists();
652
653 leaked_field_trial_list = std::make_unique<FieldTrialList>();
654 FeatureList::InitializeInstance("TestFeature1:TestParam/TestValue2", "",
655 {});
656 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
657 EXPECT_EQ("TestValue2",
658 GetFieldTrialParamValueByFeature(kTestFeature1, "TestParam"));
659 }
660 EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
661 EXPECT_EQ("TestValue1",
662 GetFieldTrialParamValueByFeature(kTestFeature1, "TestParam"));
663
664 {
665 FieldTrialList* backup_field_trial =
666 FieldTrialList::BackupInstanceForTesting();
667
668 // To free leaked_field_trial_list, need RestoreInstanceForTesting()
669 // to pass DCHECK_EQ(this, global_) at ~FieldTrialList().
670 FieldTrialList::RestoreInstanceForTesting(leaked_field_trial_list.get());
671 leaked_field_trial_list.reset();
672 FieldTrialList::RestoreInstanceForTesting(backup_field_trial);
673 }
674 }
675
TEST(ScopedFeatureListTestWithMemberList,ScopedFeatureListLocalOverride)676 TEST(ScopedFeatureListTestWithMemberList, ScopedFeatureListLocalOverride) {
677 test::ScopedFeatureList initial_feature_list;
678 initial_feature_list.InitAndDisableFeature(kTestFeature1);
679 {
680 base::test::ScopedFeatureList scoped_features;
681 scoped_features.InitAndEnableFeatureWithParameters(kTestFeature1,
682 {{"mode", "nobugs"}});
683 ASSERT_TRUE(FeatureList::IsEnabled(kTestFeature1));
684 }
685 }
686
687 } // namespace test
688 } // namespace base
689