blob: 1cef7f4eb0d023a76c5c5abf59d365372bacec98 [file] [log] [blame]
asvitkinebccbb862015-09-04 17:17:451// 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
avi9b6f42932015-12-26 22:15:147#include <stddef.h>
8
danakj0c8d4aa2015-11-25 05:29:589#include <utility>
Lily Chend49e3752019-08-09 19:05:2410#include <vector>
danakj0c8d4aa2015-11-25 05:29:5811
asvitkine8423d172015-09-28 23:23:4412#include "base/format_macros.h"
Alexandr Ilin027ca3d32019-02-12 18:37:3313#include "base/memory/read_only_shared_memory_region.h"
asvitkine8423d172015-09-28 23:23:4414#include "base/metrics/field_trial.h"
lawrencewu5e03cd32016-12-05 16:23:2815#include "base/metrics/persistent_memory_allocator.h"
Anton Bikineeva61fb572020-10-18 08:54:4416#include "base/ranges/algorithm.h"
Avi Drissmane3b70bf2019-01-04 19:50:2217#include "base/stl_util.h"
mgiuca30f75882017-03-28 02:07:1918#include "base/strings/string_piece.h"
asvitkine86340192015-12-01 00:45:2919#include "base/strings/string_util.h"
asvitkine8423d172015-09-28 23:23:4420#include "base/strings/stringprintf.h"
Wezce49a7d2019-10-08 21:47:4121#include "base/test/scoped_feature_list.h"
Mikel Astiz8a09ec12019-11-14 01:12:2322#include "base/test/scoped_field_trial_list_resetter.h"
asvitkinebccbb862015-09-04 17:17:4523#include "testing/gtest/include/gtest/gtest.h"
24
25namespace base {
26
27namespace {
28
brucedawson702ade72017-01-24 00:27:0529constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
asvitkinebccbb862015-09-04 17:17:4530struct Feature kFeatureOnByDefault {
31 kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
32};
33
brucedawson702ade72017-01-24 00:27:0534constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
asvitkinebccbb862015-09-04 17:17:4535struct Feature kFeatureOffByDefault {
36 kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
37};
38
asvitkine86340192015-12-01 00:45:2939std::string SortFeatureListString(const std::string& feature_list) {
mgiuca30f75882017-03-28 02:07:1940 std::vector<base::StringPiece> features =
asvitkine86340192015-12-01 00:45:2941 FeatureList::SplitFeatureListString(feature_list);
Anton Bikineeva61fb572020-10-18 08:54:4442 ranges::sort(features);
asvitkine86340192015-12-01 00:45:2943 return JoinString(features, ",");
44}
45
asvitkinebccbb862015-09-04 17:17:4546} // namespace
47
48class FeatureListTest : public testing::Test {
49 public:
Wezce49a7d2019-10-08 21:47:4150 FeatureListTest() {
51 // Provide an empty FeatureList to each test by default.
52 scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
asvitkinebccbb862015-09-04 17:17:4553 }
David Bienvenub4b441e2020-09-23 05:49:5754 FeatureListTest(const FeatureListTest&) = delete;
55 FeatureListTest& operator=(const FeatureListTest&) = delete;
Wezce49a7d2019-10-08 21:47:4156 ~FeatureListTest() override = default;
asvitkinebccbb862015-09-04 17:17:4557
58 private:
Wezce49a7d2019-10-08 21:47:4159 test::ScopedFeatureList scoped_feature_list_;
asvitkinebccbb862015-09-04 17:17:4560};
61
62TEST_F(FeatureListTest, DefaultStates) {
63 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
64 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
65}
66
67TEST_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
Avi Drissmane3b70bf2019-01-04 19:50:2283 for (size_t i = 0; i < base::size(test_cases); ++i) {
asvitkinebccbb862015-09-04 17:17:4584 const auto& test_case = test_cases[i];
asvitkine8423d172015-09-28 23:23:4485 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
86 test_case.enable_features,
87 test_case.disable_features));
asvitkinebccbb862015-09-04 17:17:4588
Wezce49a7d2019-10-08 21:47:4189 auto feature_list = std::make_unique<FeatureList>();
asvitkinebccbb862015-09-04 17:17:4590 feature_list->InitializeFromCommandLine(test_case.enable_features,
91 test_case.disable_features);
Wezce49a7d2019-10-08 21:47:4192 test::ScopedFeatureList scoped_feature_list;
93 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkinebccbb862015-09-04 17:17:4594
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
Weilun Shie81c6b92020-07-06 20:33:59104TEST_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>();
Weilun Shi1cd8fb92020-07-17 23:31:00122 feature_list->InitializeFromCommandLine(test_case.enable_features, "");
Weilun Shie81c6b92020-07-06 20:33:59123 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
asvitkinebccbb862015-09-04 17:17:45135TEST_F(FeatureListTest, CheckFeatureIdentity) {
136 // Tests that CheckFeatureIdentity() correctly detects when two different
137 // structs with the same feature name are passed to it.
138
Wezce49a7d2019-10-08 21:47:41139 test::ScopedFeatureList scoped_feature_list;
140 scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
141 FeatureList* feature_list = FeatureList::GetInstance();
142
asvitkinebccbb862015-09-04 17:17:45143 // 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.
Wezce49a7d2019-10-08 21:47:41145 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));
asvitkinebccbb862015-09-04 17:17:45149
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 };
Wezce49a7d2019-10-08 21:47:41155 EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
asvitkinebccbb862015-09-04 17:17:45156}
157
asvitkine8423d172015-09-28 23:23:44158TEST_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;
Avi Drissmane3b70bf2019-01-04 19:50:22174 for (size_t i = 0; i < base::size(test_cases); ++i) {
asvitkine8423d172015-09-28 23:23:44175 const auto& test_case = test_cases[i];
176 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
177
Mikel Astiz8a09ec12019-11-14 01:12:23178 test::ScopedFieldTrialListResetter resetter;
asvitkine8423d172015-09-28 23:23:44179 FieldTrialList field_trial_list(nullptr);
Wezce49a7d2019-10-08 21:47:41180 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44181
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);
Wezce49a7d2019-10-08 21:47:41188 test::ScopedFeatureList scoped_feature_list;
189 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44190
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
asvitkine64e9e112016-03-17 17:32:00211TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
Wezce49a7d2019-10-08 21:47:41212 auto feature_list = std::make_unique<FeatureList>();
asvitkine64e9e112016-03-17 17:32:00213
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);
Wezce49a7d2019-10-08 21:47:41220 test::ScopedFeatureList scoped_feature_list;
221 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine64e9e112016-03-17 17:32:00222
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
Alexei Svitkined3a55e7d42019-02-19 17:09:32240TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
Wezce49a7d2019-10-08 21:47:41241 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44242
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);
Wezce49a7d2019-10-08 21:47:41250 test::ScopedFeatureList scoped_feature_list;
251 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44252
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
Alexei Svitkined3a55e7d42019-02-19 17:09:32262TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
Wezce49a7d2019-10-08 21:47:41263 auto feature_list = std::make_unique<FeatureList>();
Alexei Svitkined3a55e7d42019-02-19 17:09:32264
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);
Wezce49a7d2019-10-08 21:47:41272 test::ScopedFeatureList scoped_feature_list;
273 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Alexei Svitkined3a55e7d42019-02-19 17:09:32274
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
Xianzhu Wang05355f4a2020-09-02 01:22:16284TEST_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
asvitkine8423d172015-09-28 23:23:44309TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
Wezce49a7d2019-10-08 21:47:41310 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44311
312 // No features are overridden from the command line yet
Xianzhu Wang05355f4a2020-09-02 01:22:16313 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09314 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
315 kFeatureOnByDefaultName));
Xianzhu Wang05355f4a2020-09-02 01:22:16316 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44317 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
Collin Baker3435ba662020-10-07 18:07:09318 kFeatureOffByDefaultName));
319 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
asvitkine8423d172015-09-28 23:23:44320 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.
Xianzhu Wang05355f4a2020-09-02 01:22:16332 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09333 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
334 kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44335 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"));
Xianzhu Wang05355f4a2020-09-02 01:22:16345 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09346 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
347 kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44348 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"));
Xianzhu Wang05355f4a2020-09-02 01:22:16358 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
asvitkine8423d172015-09-28 23:23:44359 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
Collin Baker3435ba662020-10-07 18:07:09360 kFeatureOnByDefaultName));
361 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
asvitkine8423d172015-09-28 23:23:44362 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
363 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
364 kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
Wezce49a7d2019-10-08 21:47:41365 test::ScopedFeatureList scoped_feature_list;
366 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44367
368 // Check the expected feature states for good measure.
369 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
370 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
371}
372
373TEST_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
Avi Drissmane3b70bf2019-01-04 19:50:22392 for (size_t i = 0; i < base::size(test_cases); ++i) {
asvitkine8423d172015-09-28 23:23:44393 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
Mikel Astiz8a09ec12019-11-14 01:12:23398 test::ScopedFieldTrialListResetter resetter;
asvitkine8423d172015-09-28 23:23:44399 FieldTrialList field_trial_list(nullptr);
Wezce49a7d2019-10-08 21:47:41400 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44401 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);
Wezce49a7d2019-10-08 21:47:41425 test::ScopedFeatureList scoped_feature_list;
426 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44427
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
Lily Chend49e3752019-08-09 19:05:24441TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
Lily Chend49e3752019-08-09 19:05:24442 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));
Wezce49a7d2019-10-08 21:47:41449 test::ScopedFeatureList scoped_feature_list;
450 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Lily Chend49e3752019-08-09 19:05:24451
452 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
453 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
454}
455
456TEST_F(FeatureListTest, InitializeFromCommandLineThenRegisterExtraOverrides) {
Lily Chend49e3752019-08-09 19:05:24457 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));
Wezce49a7d2019-10-08 21:47:41466 test::ScopedFeatureList scoped_feature_list;
467 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Lily Chend49e3752019-08-09 19:05:24468
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
asvitkine86340192015-12-01 00:45:29482TEST_F(FeatureListTest, GetFeatureOverrides) {
Wezce49a7d2019-10-08 21:47:41483 auto feature_list = std::make_unique<FeatureList>();
asvitkine86340192015-12-01 00:45:29484 feature_list->InitializeFromCommandLine("A,X", "D");
485
Lily Chend49e3752019-08-09 19:05:24486 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
asvitkine86340192015-12-01 00:45:29495 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
496 feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
497 FeatureList::OVERRIDE_ENABLE_FEATURE,
498 trial);
499
Wezce49a7d2019-10-08 21:47:41500 test::ScopedFeatureList scoped_feature_list;
501 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine86340192015-12-01 00:45:29502
503 std::string enable_features;
504 std::string disable_features;
505 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
506 &disable_features);
Lily Chend49e3752019-08-09 19:05:24507 EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
508 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
Alexei Svitkine223d2282018-02-08 00:18:35509
510 FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
511 &disable_features);
Lily Chend49e3752019-08-09 19:05:24512 EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
513 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
asvitkine86340192015-12-01 00:45:29514}
515
asvitkine6d31c52e2016-03-22 15:37:52516TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
Wezce49a7d2019-10-08 21:47:41517 auto feature_list = std::make_unique<FeatureList>();
asvitkine6d31c52e2016-03-22 15:37:52518 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
Wezce49a7d2019-10-08 21:47:41524 test::ScopedFeatureList scoped_feature_list;
525 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine6d31c52e2016-03-22 15:37:52526
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
jwd07b90382016-05-06 20:39:42535TEST_F(FeatureListTest, GetFieldTrial) {
jwd07b90382016-05-06 20:39:42536 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
Wezce49a7d2019-10-08 21:47:41537 auto feature_list = std::make_unique<FeatureList>();
jwd07b90382016-05-06 20:39:42538 feature_list->RegisterFieldTrialOverride(
539 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
Wezce49a7d2019-10-08 21:47:41540 test::ScopedFeatureList scoped_feature_list;
541 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
jwd07b90382016-05-06 20:39:42542
543 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
544 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
545}
546
asvitkineb2e44d82015-12-01 04:10:28547TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
asvitkineb2e44d82015-12-01 04:10:28548 FieldTrialList::CreateFieldTrial("Trial", "Group");
Wezce49a7d2019-10-08 21:47:41549 auto feature_list = std::make_unique<FeatureList>();
asvitkineb2e44d82015-12-01 04:10:28550 feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
Wezce49a7d2019-10-08 21:47:41551 test::ScopedFeatureList scoped_feature_list;
552 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkineb2e44d82015-12-01 04:10:28553
554 EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
555 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
556 EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
557}
558
asvitkine6d31c52e2016-03-22 15:37:52559TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) {
asvitkine6d31c52e2016-03-22 15:37:52560 FieldTrialList::CreateFieldTrial("T1", "Group");
561 FieldTrialList::CreateFieldTrial("T2", "Group");
Wezce49a7d2019-10-08 21:47:41562 auto feature_list = std::make_unique<FeatureList>();
asvitkine6d31c52e2016-03-22 15:37:52563 feature_list->InitializeFromCommandLine(
564 "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
Wezce49a7d2019-10-08 21:47:41565 test::ScopedFeatureList scoped_feature_list;
566 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine6d31c52e2016-03-22 15:37:52567
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
changwan5b9da192016-03-31 07:36:19577TEST_F(FeatureListTest, InitializeInstance) {
dcheng093de9b2016-04-04 21:25:51578 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Wezce49a7d2019-10-08 21:47:41579 test::ScopedFeatureList scoped_feature_list;
580 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
581
changwan5b9da192016-03-31 07:36:19582 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
joedow958f0472016-07-07 22:08:55596TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
Wezce49a7d2019-10-08 21:47:41597 std::unique_ptr<FeatureList> original_feature_list =
598 FeatureList::ClearInstanceForTesting();
599
joedow958f0472016-07-07 22:08:55600 // 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));
Wezce49a7d2019-10-08 21:47:41607
608 if (original_feature_list)
609 FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
joedow958f0472016-07-07 22:08:55610}
611
lawrencewu5e03cd32016-12-05 16:23:28612TEST_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.
Alexandr Ilin027ca3d32019-02-12 18:37:33623 base::MappedReadOnlyRegion shm =
624 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
625 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
626 "");
lawrencewu5e03cd32016-12-05 16:23:28627 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
645TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
lawrencewu5e03cd32016-12-05 16:23:28646 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.
Alexandr Ilin027ca3d32019-02-12 18:37:33658 base::MappedReadOnlyRegion shm =
659 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
660 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
661 "");
lawrencewu5e03cd32016-12-05 16:23:28662 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
asvitkinebccbb862015-09-04 17:17:45677} // namespace base