1 // Copyright 2015 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 "base/feature_list.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10 #include <vector>
11
12 #include "base/format_macros.h"
13 #include "base/memory/read_only_shared_memory_region.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/persistent_memory_allocator.h"
16 #include "base/ranges/algorithm.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/test/scoped_feature_list.h"
22 #include "base/test/scoped_field_trial_list_resetter.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace base {
26
27 namespace {
28
29 constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
30 struct Feature kFeatureOnByDefault {
31 kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
32 };
33
34 constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
35 struct Feature kFeatureOffByDefault {
36 kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
37 };
38
SortFeatureListString(const std::string & feature_list)39 std::string SortFeatureListString(const std::string& feature_list) {
40 std::vector<base::StringPiece> features =
41 FeatureList::SplitFeatureListString(feature_list);
42 ranges::sort(features);
43 return JoinString(features, ",");
44 }
45
46 } // namespace
47
48 class FeatureListTest : public testing::Test {
49 public:
FeatureListTest()50 FeatureListTest() {
51 // Provide an empty FeatureList to each test by default.
52 scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
53 }
54 FeatureListTest(const FeatureListTest&) = delete;
55 FeatureListTest& operator=(const FeatureListTest&) = delete;
56 ~FeatureListTest() override = default;
57
58 private:
59 test::ScopedFeatureList scoped_feature_list_;
60 };
61
TEST_F(FeatureListTest,DefaultStates)62 TEST_F(FeatureListTest, DefaultStates) {
63 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
64 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
65 }
66
TEST_F(FeatureListTest,InitializeFromCommandLine)67 TEST_F(FeatureListTest, InitializeFromCommandLine) {
68 struct {
69 const char* enable_features;
70 const char* disable_features;
71 bool expected_feature_on_state;
72 bool expected_feature_off_state;
73 } test_cases[] = {
74 {"", "", true, false},
75 {"OffByDefault", "", true, true},
76 {"OffByDefault", "OnByDefault", false, true},
77 {"OnByDefault,OffByDefault", "", true, true},
78 {"", "OnByDefault,OffByDefault", false, false},
79 // In the case an entry is both, disable takes precedence.
80 {"OnByDefault", "OnByDefault,OffByDefault", false, false},
81 };
82
83 for (size_t i = 0; i < base::size(test_cases); ++i) {
84 const auto& test_case = test_cases[i];
85 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
86 test_case.enable_features,
87 test_case.disable_features));
88
89 auto feature_list = std::make_unique<FeatureList>();
90 feature_list->InitializeFromCommandLine(test_case.enable_features,
91 test_case.disable_features);
92 test::ScopedFeatureList scoped_feature_list;
93 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
94
95 EXPECT_EQ(test_case.expected_feature_on_state,
96 FeatureList::IsEnabled(kFeatureOnByDefault))
97 << i;
98 EXPECT_EQ(test_case.expected_feature_off_state,
99 FeatureList::IsEnabled(kFeatureOffByDefault))
100 << i;
101 }
102 }
103
TEST_F(FeatureListTest,InitializeFromCommandLineWithFeatureParams)104 TEST_F(FeatureListTest, InitializeFromCommandLineWithFeatureParams) {
105 struct {
106 const std::string enable_features;
107 const std::string expected_field_trial_created;
108 const std::map<std::string, std::string> expected_feature_params;
109 } test_cases[] = {
110 {"Feature:x/100/y/test", "StudyFeature", {{"x", "100"}, {"y", "test"}}},
111 {"Feature<Trial1:x/200/y/123", "Trial1", {{"x", "200"}, {"y", "123"}}},
112 {"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
113 "Trial2",
114 {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
115 };
116
117 const Feature kFeature = {"Feature", FEATURE_DISABLED_BY_DEFAULT};
118 for (const auto& test_case : test_cases) {
119 SCOPED_TRACE(test_case.enable_features);
120
121 auto feature_list = std::make_unique<FeatureList>();
122 feature_list->InitializeFromCommandLine(test_case.enable_features, "");
123 test::ScopedFeatureList scoped_feature_list;
124 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
125
126 EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
127 EXPECT_TRUE(
128 FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
129 std::map<std::string, std::string> actualParams;
130 EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actualParams));
131 EXPECT_EQ(test_case.expected_feature_params, actualParams);
132 }
133 }
134
TEST_F(FeatureListTest,CheckFeatureIdentity)135 TEST_F(FeatureListTest, CheckFeatureIdentity) {
136 // Tests that CheckFeatureIdentity() correctly detects when two different
137 // structs with the same feature name are passed to it.
138
139 test::ScopedFeatureList scoped_feature_list;
140 scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
141 FeatureList* feature_list = FeatureList::GetInstance();
142
143 // Call it twice for each feature at the top of the file, since the first call
144 // makes it remember the entry and the second call will verify it.
145 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
146 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
147 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
148 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
149
150 // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
151 // should return false.
152 struct Feature kFeatureOnByDefault2 {
153 kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
154 };
155 EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
156 }
157
TEST_F(FeatureListTest,FieldTrialOverrides)158 TEST_F(FeatureListTest, FieldTrialOverrides) {
159 struct {
160 FeatureList::OverrideState trial1_state;
161 FeatureList::OverrideState trial2_state;
162 } test_cases[] = {
163 {FeatureList::OVERRIDE_DISABLE_FEATURE,
164 FeatureList::OVERRIDE_DISABLE_FEATURE},
165 {FeatureList::OVERRIDE_DISABLE_FEATURE,
166 FeatureList::OVERRIDE_ENABLE_FEATURE},
167 {FeatureList::OVERRIDE_ENABLE_FEATURE,
168 FeatureList::OVERRIDE_DISABLE_FEATURE},
169 {FeatureList::OVERRIDE_ENABLE_FEATURE,
170 FeatureList::OVERRIDE_ENABLE_FEATURE},
171 };
172
173 FieldTrial::ActiveGroup active_group;
174 for (size_t i = 0; i < base::size(test_cases); ++i) {
175 const auto& test_case = test_cases[i];
176 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
177
178 test::ScopedFieldTrialListResetter resetter;
179 FieldTrialList field_trial_list(nullptr);
180 auto feature_list = std::make_unique<FeatureList>();
181
182 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
183 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
184 feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
185 test_case.trial1_state, trial1);
186 feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
187 test_case.trial2_state, trial2);
188 test::ScopedFeatureList scoped_feature_list;
189 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
190
191 // Initially, neither trial should be active.
192 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
193 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
194
195 const bool expected_enabled_1 =
196 (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
197 EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
198 // The above should have activated |trial1|.
199 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
200 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
201
202 const bool expected_enabled_2 =
203 (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
204 EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
205 // The above should have activated |trial2|.
206 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
207 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
208 }
209 }
210
TEST_F(FeatureListTest,FieldTrialAssociateUseDefault)211 TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
212 auto feature_list = std::make_unique<FeatureList>();
213
214 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
215 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
216 feature_list->RegisterFieldTrialOverride(
217 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
218 feature_list->RegisterFieldTrialOverride(
219 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
220 test::ScopedFeatureList scoped_feature_list;
221 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
222
223 // Initially, neither trial should be active.
224 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
225 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
226
227 // Check the feature enabled state is its default.
228 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
229 // The above should have activated |trial1|.
230 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
231 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
232
233 // Check the feature enabled state is its default.
234 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
235 // The above should have activated |trial2|.
236 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
237 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
238 }
239
TEST_F(FeatureListTest,CommandLineEnableTakesPrecedenceOverFieldTrial)240 TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
241 auto feature_list = std::make_unique<FeatureList>();
242
243 // The feature is explicitly enabled on the command-line.
244 feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
245
246 // But the FieldTrial would set the feature to disabled.
247 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
248 feature_list->RegisterFieldTrialOverride(
249 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
250 test::ScopedFeatureList scoped_feature_list;
251 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
252
253 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
254 // Command-line should take precedence.
255 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
256 // Since the feature is on due to the command-line, and not as a result of the
257 // field trial, the field trial should not be activated (since the Associate*
258 // API wasn't used.)
259 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
260 }
261
TEST_F(FeatureListTest,CommandLineDisableTakesPrecedenceOverFieldTrial)262 TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
263 auto feature_list = std::make_unique<FeatureList>();
264
265 // The feature is explicitly disabled on the command-line.
266 feature_list->InitializeFromCommandLine("", kFeatureOffByDefaultName);
267
268 // But the FieldTrial would set the feature to enabled.
269 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
270 feature_list->RegisterFieldTrialOverride(
271 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
272 test::ScopedFeatureList scoped_feature_list;
273 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
274
275 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
276 // Command-line should take precedence.
277 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
278 // Since the feature is on due to the command-line, and not as a result of the
279 // field trial, the field trial should not be activated (since the Associate*
280 // API wasn't used.)
281 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
282 }
283
TEST_F(FeatureListTest,IsFeatureOverriddenFromFieldTrial)284 TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
285 auto feature_list = std::make_unique<FeatureList>();
286
287 // No features are overridden from the field trails yet.
288 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
289 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
290
291 // Now, register a field trial to override |kFeatureOnByDefaultName| state
292 // and check that the function still returns false for that feature.
293 feature_list->RegisterFieldTrialOverride(
294 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT,
295 FieldTrialList::CreateFieldTrial("Trial1", "A"));
296 feature_list->RegisterFieldTrialOverride(
297 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
298 FieldTrialList::CreateFieldTrial("Trial2", "A"));
299 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
300 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
301
302 test::ScopedFeatureList scoped_feature_list;
303 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
304 // Check the expected feature states for good measure.
305 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
306 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
307 }
308
TEST_F(FeatureListTest,IsFeatureOverriddenFromCommandLine)309 TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
310 auto feature_list = std::make_unique<FeatureList>();
311
312 // No features are overridden from the command line yet
313 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
314 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
315 kFeatureOnByDefaultName));
316 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
317 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
318 kFeatureOffByDefaultName));
319 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
320 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
321 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
322 kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
323 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
324 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
325 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
326 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
327
328 // Now, enable |kFeatureOffByDefaultName| via the command-line.
329 feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
330
331 // It should now be overridden for the enabled group.
332 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
333 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
334 kFeatureOffByDefaultName));
335 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
336 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
337 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
338 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
339
340 // Register a field trial to associate with the feature and ensure that the
341 // results are still the same.
342 feature_list->AssociateReportingFieldTrial(
343 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
344 FieldTrialList::CreateFieldTrial("Trial1", "A"));
345 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
346 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
347 kFeatureOffByDefaultName));
348 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
349 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
350 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
351 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
352
353 // Now, register a field trial to override |kFeatureOnByDefaultName| state
354 // and check that the function still returns false for that feature.
355 feature_list->RegisterFieldTrialOverride(
356 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
357 FieldTrialList::CreateFieldTrial("Trial2", "A"));
358 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
359 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
360 kFeatureOnByDefaultName));
361 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
362 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
363 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
364 kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
365 test::ScopedFeatureList scoped_feature_list;
366 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
367
368 // Check the expected feature states for good measure.
369 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
370 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
371 }
372
TEST_F(FeatureListTest,AssociateReportingFieldTrial)373 TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
374 struct {
375 const char* enable_features;
376 const char* disable_features;
377 bool expected_enable_trial_created;
378 bool expected_disable_trial_created;
379 } test_cases[] = {
380 // If no enable/disable flags are specified, no trials should be created.
381 {"", "", false, false},
382 // Enabling the feature should result in the enable trial created.
383 {kFeatureOffByDefaultName, "", true, false},
384 // Disabling the feature should result in the disable trial created.
385 {"", kFeatureOffByDefaultName, false, true},
386 };
387
388 const char kTrialName[] = "ForcingTrial";
389 const char kForcedOnGroupName[] = "ForcedOn";
390 const char kForcedOffGroupName[] = "ForcedOff";
391
392 for (size_t i = 0; i < base::size(test_cases); ++i) {
393 const auto& test_case = test_cases[i];
394 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
395 test_case.enable_features,
396 test_case.disable_features));
397
398 test::ScopedFieldTrialListResetter resetter;
399 FieldTrialList field_trial_list(nullptr);
400 auto feature_list = std::make_unique<FeatureList>();
401 feature_list->InitializeFromCommandLine(test_case.enable_features,
402 test_case.disable_features);
403
404 FieldTrial* enable_trial = nullptr;
405 if (feature_list->IsFeatureOverriddenFromCommandLine(
406 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
407 enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
408 kForcedOnGroupName);
409 feature_list->AssociateReportingFieldTrial(
410 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
411 enable_trial);
412 }
413 FieldTrial* disable_trial = nullptr;
414 if (feature_list->IsFeatureOverriddenFromCommandLine(
415 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
416 disable_trial = base::FieldTrialList::CreateFieldTrial(
417 kTrialName, kForcedOffGroupName);
418 feature_list->AssociateReportingFieldTrial(
419 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
420 disable_trial);
421 }
422 EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
423 EXPECT_EQ(test_case.expected_disable_trial_created,
424 disable_trial != nullptr);
425 test::ScopedFeatureList scoped_feature_list;
426 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
427
428 EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
429 if (disable_trial) {
430 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
431 EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
432 EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
433 } else if (enable_trial) {
434 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
435 EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
436 EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
437 }
438 }
439 }
440
TEST_F(FeatureListTest,RegisterExtraFeatureOverrides)441 TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
442 auto feature_list = std::make_unique<FeatureList>();
443 std::vector<FeatureList::FeatureOverrideInfo> overrides;
444 overrides.push_back({std::cref(kFeatureOnByDefault),
445 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
446 overrides.push_back({std::cref(kFeatureOffByDefault),
447 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
448 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
449 test::ScopedFeatureList scoped_feature_list;
450 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
451
452 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
453 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
454 }
455
TEST_F(FeatureListTest,InitializeFromCommandLineThenRegisterExtraOverrides)456 TEST_F(FeatureListTest, InitializeFromCommandLineThenRegisterExtraOverrides) {
457 auto feature_list = std::make_unique<FeatureList>();
458 feature_list->InitializeFromCommandLine(kFeatureOnByDefaultName,
459 kFeatureOffByDefaultName);
460 std::vector<FeatureList::FeatureOverrideInfo> overrides;
461 overrides.push_back({std::cref(kFeatureOnByDefault),
462 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
463 overrides.push_back({std::cref(kFeatureOffByDefault),
464 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
465 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
466 test::ScopedFeatureList scoped_feature_list;
467 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
468
469 // The InitializeFromCommandLine supersedes the RegisterExtraFeatureOverrides
470 // because it was called first.
471 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
472 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
473
474 std::string enable_features;
475 std::string disable_features;
476 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
477 &disable_features);
478 EXPECT_EQ(kFeatureOnByDefaultName, SortFeatureListString(enable_features));
479 EXPECT_EQ(kFeatureOffByDefaultName, SortFeatureListString(disable_features));
480 }
481
TEST_F(FeatureListTest,GetFeatureOverrides)482 TEST_F(FeatureListTest, GetFeatureOverrides) {
483 auto feature_list = std::make_unique<FeatureList>();
484 feature_list->InitializeFromCommandLine("A,X", "D");
485
486 Feature feature_b = {"B", FEATURE_ENABLED_BY_DEFAULT};
487 Feature feature_c = {"C", FEATURE_DISABLED_BY_DEFAULT};
488 std::vector<FeatureList::FeatureOverrideInfo> overrides;
489 overrides.push_back({std::cref(feature_b),
490 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
491 overrides.push_back({std::cref(feature_c),
492 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
493 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
494
495 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
496 feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
497 FeatureList::OVERRIDE_ENABLE_FEATURE,
498 trial);
499
500 test::ScopedFeatureList scoped_feature_list;
501 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
502
503 std::string enable_features;
504 std::string disable_features;
505 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
506 &disable_features);
507 EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
508 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
509
510 FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
511 &disable_features);
512 EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
513 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
514 }
515
TEST_F(FeatureListTest,GetFeatureOverrides_UseDefault)516 TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
517 auto feature_list = std::make_unique<FeatureList>();
518 feature_list->InitializeFromCommandLine("A,X", "D");
519
520 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
521 feature_list->RegisterFieldTrialOverride(
522 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
523
524 test::ScopedFeatureList scoped_feature_list;
525 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
526
527 std::string enable_features;
528 std::string disable_features;
529 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
530 &disable_features);
531 EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
532 EXPECT_EQ("D", SortFeatureListString(disable_features));
533 }
534
TEST_F(FeatureListTest,GetFieldTrial)535 TEST_F(FeatureListTest, GetFieldTrial) {
536 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
537 auto feature_list = std::make_unique<FeatureList>();
538 feature_list->RegisterFieldTrialOverride(
539 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
540 test::ScopedFeatureList scoped_feature_list;
541 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
542
543 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
544 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
545 }
546
TEST_F(FeatureListTest,InitializeFromCommandLine_WithFieldTrials)547 TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
548 FieldTrialList::CreateFieldTrial("Trial", "Group");
549 auto feature_list = std::make_unique<FeatureList>();
550 feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
551 test::ScopedFeatureList scoped_feature_list;
552 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
553
554 EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
555 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
556 EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
557 }
558
TEST_F(FeatureListTest,InitializeFromCommandLine_UseDefault)559 TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) {
560 FieldTrialList::CreateFieldTrial("T1", "Group");
561 FieldTrialList::CreateFieldTrial("T2", "Group");
562 auto feature_list = std::make_unique<FeatureList>();
563 feature_list->InitializeFromCommandLine(
564 "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
565 test::ScopedFeatureList scoped_feature_list;
566 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
567
568 EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
569 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
570 EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
571
572 EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
573 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
574 EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
575 }
576
TEST_F(FeatureListTest,InitializeInstance)577 TEST_F(FeatureListTest, InitializeInstance) {
578 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
579 test::ScopedFeatureList scoped_feature_list;
580 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
581
582 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
583 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
584
585 // Initialize from command line if we haven't yet.
586 FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
587 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
588 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
589
590 // Do not initialize from commandline if we have already.
591 FeatureList::InitializeInstance(kFeatureOffByDefaultName, "");
592 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
593 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
594 }
595
TEST_F(FeatureListTest,UninitializedInstance_IsEnabledReturnsFalse)596 TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
597 std::unique_ptr<FeatureList> original_feature_list =
598 FeatureList::ClearInstanceForTesting();
599
600 // This test case simulates the calling pattern found in code which does not
601 // explicitly initialize the features list.
602 // All IsEnabled() calls should return the default value in this scenario.
603 EXPECT_EQ(nullptr, FeatureList::GetInstance());
604 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
605 EXPECT_EQ(nullptr, FeatureList::GetInstance());
606 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
607
608 if (original_feature_list)
609 FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
610 }
611
TEST_F(FeatureListTest,StoreAndRetrieveFeaturesFromSharedMemory)612 TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {
613 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
614
615 // Create some overrides.
616 feature_list->RegisterOverride(kFeatureOffByDefaultName,
617 FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
618 feature_list->RegisterOverride(
619 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
620 feature_list->FinalizeInitialization();
621
622 // Create an allocator and store the overrides.
623 base::MappedReadOnlyRegion shm =
624 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
625 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
626 "");
627 feature_list->AddFeaturesToAllocator(&allocator);
628
629 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
630
631 // Check that the new feature list is empty.
632 EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
633 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
634 EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
635 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
636
637 feature_list2->InitializeFromSharedMemory(&allocator);
638 // Check that the new feature list now has 2 overrides.
639 EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
640 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
641 EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
642 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
643 }
644
TEST_F(FeatureListTest,StoreAndRetrieveAssociatedFeaturesFromSharedMemory)645 TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
646 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
647
648 // Create some overrides.
649 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
650 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
651 feature_list->RegisterFieldTrialOverride(
652 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
653 feature_list->RegisterFieldTrialOverride(
654 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
655 feature_list->FinalizeInitialization();
656
657 // Create an allocator and store the overrides.
658 base::MappedReadOnlyRegion shm =
659 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
660 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
661 "");
662 feature_list->AddFeaturesToAllocator(&allocator);
663
664 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
665 feature_list2->InitializeFromSharedMemory(&allocator);
666 feature_list2->FinalizeInitialization();
667
668 // Check that the field trials are still associated.
669 FieldTrial* associated_trial1 =
670 feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
671 FieldTrial* associated_trial2 =
672 feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
673 EXPECT_EQ(associated_trial1, trial1);
674 EXPECT_EQ(associated_trial2, trial2);
675 }
676
677 } // namespace base
678