blob: d0867732b30b10c17e742eb6ac7a06deccdbe3df [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2015 The Chromium Authors
asvitkinebccbb862015-09-04 17:17:452// 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
Peter Kasting025a94252025-01-29 21:28:379#include <algorithm>
Arthur Sonzogni0844a992024-12-12 11:36:2010#include <array>
Kendrake Tsuid3895ec2024-01-22 22:08:3911#include <ostream>
12#include <set>
13#include <string>
Helmut Januschkabf1d5e52024-04-05 02:30:2714#include <string_view>
danakj0c8d4aa2015-11-25 05:29:5815#include <utility>
Lily Chend49e3752019-08-09 19:05:2416#include <vector>
danakj0c8d4aa2015-11-25 05:29:5817
Miriam Zimmermanb4683c12021-12-01 15:44:3318#include "base/feature_list_buildflags.h"
Leszek Swirskif7f53b432024-09-30 10:12:1019#include "base/feature_visitor.h"
asvitkine8423d172015-09-28 23:23:4420#include "base/format_macros.h"
Alexandr Ilin027ca3d32019-02-12 18:37:3321#include "base/memory/read_only_shared_memory_region.h"
asvitkine8423d172015-09-28 23:23:4422#include "base/metrics/field_trial.h"
Miriam Zimmerman79f6cac2022-06-17 17:58:2523#include "base/metrics/field_trial_param_associator.h"
lawrencewu5e03cd32016-12-05 16:23:2824#include "base/metrics/persistent_memory_allocator.h"
Miriam Zimmermanb4683c12021-12-01 15:44:3325#include "base/strings/strcat.h"
asvitkine86340192015-12-01 00:45:2926#include "base/strings/string_util.h"
asvitkine8423d172015-09-28 23:23:4427#include "base/strings/stringprintf.h"
Wezce49a7d2019-10-08 21:47:4128#include "base/test/scoped_feature_list.h"
asvitkinebccbb862015-09-04 17:17:4529#include "testing/gtest/include/gtest/gtest.h"
30
31namespace base {
32
33namespace {
34
brucedawson702ade72017-01-24 00:27:0535constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
Daniel Cheng2628f682024-05-03 16:18:4536BASE_FEATURE(kFeatureOnByDefault,
37 kFeatureOnByDefaultName,
38 FEATURE_ENABLED_BY_DEFAULT);
asvitkinebccbb862015-09-04 17:17:4539
brucedawson702ade72017-01-24 00:27:0540constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
Daniel Cheng2628f682024-05-03 16:18:4541BASE_FEATURE(kFeatureOffByDefault,
42 kFeatureOffByDefaultName,
43 FEATURE_DISABLED_BY_DEFAULT);
asvitkinebccbb862015-09-04 17:17:4544
asvitkine86340192015-12-01 00:45:2945std::string SortFeatureListString(const std::string& feature_list) {
Helmut Januschkabf1d5e52024-04-05 02:30:2746 std::vector<std::string_view> features =
asvitkine86340192015-12-01 00:45:2947 FeatureList::SplitFeatureListString(feature_list);
Peter Kasting025a94252025-01-29 21:28:3748 std::ranges::sort(features);
asvitkine86340192015-12-01 00:45:2949 return JoinString(features, ",");
50}
51
asvitkinebccbb862015-09-04 17:17:4552} // namespace
53
54class FeatureListTest : public testing::Test {
55 public:
Wezce49a7d2019-10-08 21:47:4156 FeatureListTest() {
57 // Provide an empty FeatureList to each test by default.
58 scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
asvitkinebccbb862015-09-04 17:17:4559 }
David Bienvenub4b441e2020-09-23 05:49:5760 FeatureListTest(const FeatureListTest&) = delete;
61 FeatureListTest& operator=(const FeatureListTest&) = delete;
Wezce49a7d2019-10-08 21:47:4162 ~FeatureListTest() override = default;
asvitkinebccbb862015-09-04 17:17:4563
64 private:
Wezce49a7d2019-10-08 21:47:4165 test::ScopedFeatureList scoped_feature_list_;
asvitkinebccbb862015-09-04 17:17:4566};
67
68TEST_F(FeatureListTest, DefaultStates) {
69 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
70 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
71}
72
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:1973TEST_F(FeatureListTest, InitFromCommandLine) {
Arthur Sonzogni0844a992024-12-12 11:36:2074 struct TestCases {
asvitkinebccbb862015-09-04 17:17:4575 const char* enable_features;
76 const char* disable_features;
77 bool expected_feature_on_state;
78 bool expected_feature_off_state;
Arthur Sonzogni0844a992024-12-12 11:36:2079 };
80 auto test_cases = std::to_array<TestCases>({
asvitkinebccbb862015-09-04 17:17:4581 {"", "", true, false},
82 {"OffByDefault", "", true, true},
83 {"OffByDefault", "OnByDefault", false, true},
84 {"OnByDefault,OffByDefault", "", true, true},
85 {"", "OnByDefault,OffByDefault", false, false},
86 // In the case an entry is both, disable takes precedence.
87 {"OnByDefault", "OnByDefault,OffByDefault", false, false},
Arthur Sonzogni0844a992024-12-12 11:36:2088 });
asvitkinebccbb862015-09-04 17:17:4589
Daniel Chengf45f47602022-02-28 22:38:3290 for (size_t i = 0; i < std::size(test_cases); ++i) {
asvitkinebccbb862015-09-04 17:17:4591 const auto& test_case = test_cases[i];
asvitkine8423d172015-09-28 23:23:4492 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
93 test_case.enable_features,
94 test_case.disable_features));
asvitkinebccbb862015-09-04 17:17:4595
Wezce49a7d2019-10-08 21:47:4196 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:1997 feature_list->InitFromCommandLine(test_case.enable_features,
98 test_case.disable_features);
Wezce49a7d2019-10-08 21:47:4199 test::ScopedFeatureList scoped_feature_list;
100 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkinebccbb862015-09-04 17:17:45101
102 EXPECT_EQ(test_case.expected_feature_on_state,
103 FeatureList::IsEnabled(kFeatureOnByDefault))
104 << i;
105 EXPECT_EQ(test_case.expected_feature_off_state,
106 FeatureList::IsEnabled(kFeatureOffByDefault))
107 << i;
Anthony Vallee-Dubois3475f662022-08-30 14:24:28108
109 // Reading the state of each feature again will pull it from their
110 // respective caches instead of performing the full lookup, which should
111 // yield the same result.
112 EXPECT_EQ(test_case.expected_feature_on_state,
113 FeatureList::IsEnabled(kFeatureOnByDefault))
114 << i;
115 EXPECT_EQ(test_case.expected_feature_off_state,
116 FeatureList::IsEnabled(kFeatureOffByDefault))
117 << i;
asvitkinebccbb862015-09-04 17:17:45118 }
119}
120
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19121TEST_F(FeatureListTest, InitFromCommandLineWithFeatureParams) {
Weilun Shie81c6b92020-07-06 20:33:59122 struct {
123 const std::string enable_features;
124 const std::string expected_field_trial_created;
125 const std::map<std::string, std::string> expected_feature_params;
126 } test_cases[] = {
127 {"Feature:x/100/y/test", "StudyFeature", {{"x", "100"}, {"y", "test"}}},
128 {"Feature<Trial1:x/200/y/123", "Trial1", {{"x", "200"}, {"y", "123"}}},
129 {"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
130 "Trial2",
131 {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
132 };
133
Miriam Zimmerman79f6cac2022-06-17 17:58:25134 // Clear global state so that repeated runs of this test don't flake.
135 // When https://crrev.com/c/3694674 is submitted, we should be able to remove
136 // this.
137 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
138
Daniel Cheng0fff5c232022-09-21 17:43:34139 static BASE_FEATURE(kFeature, "Feature", FEATURE_DISABLED_BY_DEFAULT);
Weilun Shie81c6b92020-07-06 20:33:59140 for (const auto& test_case : test_cases) {
141 SCOPED_TRACE(test_case.enable_features);
142
143 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19144 feature_list->InitFromCommandLine(test_case.enable_features, "");
Weilun Shie81c6b92020-07-06 20:33:59145 test::ScopedFeatureList scoped_feature_list;
146 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
147
148 EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
149 EXPECT_TRUE(
150 FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
Miriam Zimmerman79f6cac2022-06-17 17:58:25151 std::map<std::string, std::string> actual_params;
152 EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actual_params));
153 EXPECT_EQ(test_case.expected_feature_params, actual_params);
Weilun Shie81c6b92020-07-06 20:33:59154 }
155}
156
asvitkinebccbb862015-09-04 17:17:45157TEST_F(FeatureListTest, CheckFeatureIdentity) {
158 // Tests that CheckFeatureIdentity() correctly detects when two different
159 // structs with the same feature name are passed to it.
160
Wezce49a7d2019-10-08 21:47:41161 test::ScopedFeatureList scoped_feature_list;
162 scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
163 FeatureList* feature_list = FeatureList::GetInstance();
164
asvitkinebccbb862015-09-04 17:17:45165 // Call it twice for each feature at the top of the file, since the first call
166 // makes it remember the entry and the second call will verify it.
Wezce49a7d2019-10-08 21:47:41167 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
168 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
169 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
170 EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
asvitkinebccbb862015-09-04 17:17:45171
172 // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
173 // should return false.
Daniel Cheng2628f682024-05-03 16:18:45174 static BASE_FEATURE(kFeatureOnByDefault2, kFeatureOnByDefaultName,
175 FEATURE_ENABLED_BY_DEFAULT);
Wezce49a7d2019-10-08 21:47:41176 EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
asvitkinebccbb862015-09-04 17:17:45177}
178
asvitkine8423d172015-09-28 23:23:44179TEST_F(FeatureListTest, FieldTrialOverrides) {
Arthur Sonzogni0844a992024-12-12 11:36:20180 struct TestCases {
asvitkine8423d172015-09-28 23:23:44181 FeatureList::OverrideState trial1_state;
182 FeatureList::OverrideState trial2_state;
asvitkine8423d172015-09-28 23:23:44183 };
Arthur Sonzogni0844a992024-12-12 11:36:20184 auto test_cases = std::to_array<TestCases>({
185 {FeatureList::OVERRIDE_DISABLE_FEATURE,
186 FeatureList::OVERRIDE_DISABLE_FEATURE},
187 {FeatureList::OVERRIDE_DISABLE_FEATURE,
188 FeatureList::OVERRIDE_ENABLE_FEATURE},
189 {FeatureList::OVERRIDE_ENABLE_FEATURE,
190 FeatureList::OVERRIDE_DISABLE_FEATURE},
191 {FeatureList::OVERRIDE_ENABLE_FEATURE,
192 FeatureList::OVERRIDE_ENABLE_FEATURE},
193 });
asvitkine8423d172015-09-28 23:23:44194
195 FieldTrial::ActiveGroup active_group;
Daniel Chengf45f47602022-02-28 22:38:32196 for (size_t i = 0; i < std::size(test_cases); ++i) {
asvitkine8423d172015-09-28 23:23:44197 const auto& test_case = test_cases[i];
198 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
199
Takashi Sakamoto15d4a672022-08-05 07:24:16200 test::ScopedFeatureList outer_scope;
201 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
202
Wezce49a7d2019-10-08 21:47:41203 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44204
205 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
206 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
207 feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
208 test_case.trial1_state, trial1);
209 feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
210 test_case.trial2_state, trial2);
Wezce49a7d2019-10-08 21:47:41211 test::ScopedFeatureList scoped_feature_list;
212 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44213
214 // Initially, neither trial should be active.
215 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
216 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
217
218 const bool expected_enabled_1 =
219 (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
220 EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
221 // The above should have activated |trial1|.
222 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
223 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
224
225 const bool expected_enabled_2 =
226 (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
227 EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
228 // The above should have activated |trial2|.
229 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
230 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
231 }
232}
233
asvitkine64e9e112016-03-17 17:32:00234TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
Wezce49a7d2019-10-08 21:47:41235 auto feature_list = std::make_unique<FeatureList>();
asvitkine64e9e112016-03-17 17:32:00236
237 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
238 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
239 feature_list->RegisterFieldTrialOverride(
240 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
241 feature_list->RegisterFieldTrialOverride(
242 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
Wezce49a7d2019-10-08 21:47:41243 test::ScopedFeatureList scoped_feature_list;
244 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine64e9e112016-03-17 17:32:00245
246 // Initially, neither trial should be active.
247 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
248 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
249
250 // Check the feature enabled state is its default.
251 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
252 // The above should have activated |trial1|.
253 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
254 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
255
256 // Check the feature enabled state is its default.
257 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
258 // The above should have activated |trial2|.
259 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
260 EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
261}
262
Alexei Svitkined3a55e7d42019-02-19 17:09:32263TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
Wezce49a7d2019-10-08 21:47:41264 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44265
266 // The feature is explicitly enabled on the command-line.
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19267 feature_list->InitFromCommandLine(kFeatureOffByDefaultName, "");
asvitkine8423d172015-09-28 23:23:44268
269 // But the FieldTrial would set the feature to disabled.
270 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
271 feature_list->RegisterFieldTrialOverride(
272 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
Wezce49a7d2019-10-08 21:47:41273 test::ScopedFeatureList scoped_feature_list;
274 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44275
276 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
277 // Command-line should take precedence.
278 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
279 // Since the feature is on due to the command-line, and not as a result of the
280 // field trial, the field trial should not be activated (since the Associate*
281 // API wasn't used.)
282 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
283}
284
Alexei Svitkined3a55e7d42019-02-19 17:09:32285TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
Wezce49a7d2019-10-08 21:47:41286 auto feature_list = std::make_unique<FeatureList>();
Alexei Svitkined3a55e7d42019-02-19 17:09:32287
288 // The feature is explicitly disabled on the command-line.
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19289 feature_list->InitFromCommandLine("", kFeatureOffByDefaultName);
Alexei Svitkined3a55e7d42019-02-19 17:09:32290
291 // But the FieldTrial would set the feature to enabled.
292 FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
293 feature_list->RegisterFieldTrialOverride(
294 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
Wezce49a7d2019-10-08 21:47:41295 test::ScopedFeatureList scoped_feature_list;
296 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Alexei Svitkined3a55e7d42019-02-19 17:09:32297
298 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
299 // Command-line should take precedence.
300 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
301 // Since the feature is on due to the command-line, and not as a result of the
302 // field trial, the field trial should not be activated (since the Associate*
303 // API wasn't used.)
304 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
305}
306
Xianzhu Wang05355f4a2020-09-02 01:22:16307TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
308 auto feature_list = std::make_unique<FeatureList>();
309
310 // No features are overridden from the field trails yet.
311 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
312 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
313
314 // Now, register a field trial to override |kFeatureOnByDefaultName| state
315 // and check that the function still returns false for that feature.
316 feature_list->RegisterFieldTrialOverride(
317 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT,
318 FieldTrialList::CreateFieldTrial("Trial1", "A"));
319 feature_list->RegisterFieldTrialOverride(
320 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
321 FieldTrialList::CreateFieldTrial("Trial2", "A"));
322 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
323 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
324
325 test::ScopedFeatureList scoped_feature_list;
326 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
327 // Check the expected feature states for good measure.
328 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
329 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
330}
331
asvitkine8423d172015-09-28 23:23:44332TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
Wezce49a7d2019-10-08 21:47:41333 auto feature_list = std::make_unique<FeatureList>();
asvitkine8423d172015-09-28 23:23:44334
335 // No features are overridden from the command line yet
Xianzhu Wang05355f4a2020-09-02 01:22:16336 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09337 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
338 kFeatureOnByDefaultName));
Xianzhu Wang05355f4a2020-09-02 01:22:16339 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44340 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
Collin Baker3435ba662020-10-07 18:07:09341 kFeatureOffByDefaultName));
342 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
asvitkine8423d172015-09-28 23:23:44343 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
344 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
345 kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
346 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
347 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
348 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
349 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
350
351 // Now, enable |kFeatureOffByDefaultName| via the command-line.
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19352 feature_list->InitFromCommandLine(kFeatureOffByDefaultName, "");
asvitkine8423d172015-09-28 23:23:44353
354 // It should now be overridden for the enabled group.
Xianzhu Wang05355f4a2020-09-02 01:22:16355 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09356 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
357 kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44358 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
359 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
360 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
361 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
362
363 // Register a field trial to associate with the feature and ensure that the
364 // results are still the same.
365 feature_list->AssociateReportingFieldTrial(
366 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
367 FieldTrialList::CreateFieldTrial("Trial1", "A"));
Xianzhu Wang05355f4a2020-09-02 01:22:16368 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
Collin Baker3435ba662020-10-07 18:07:09369 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
370 kFeatureOffByDefaultName));
asvitkine8423d172015-09-28 23:23:44371 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
372 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
373 EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
374 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
375
376 // Now, register a field trial to override |kFeatureOnByDefaultName| state
377 // and check that the function still returns false for that feature.
378 feature_list->RegisterFieldTrialOverride(
379 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
380 FieldTrialList::CreateFieldTrial("Trial2", "A"));
Xianzhu Wang05355f4a2020-09-02 01:22:16381 EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
asvitkine8423d172015-09-28 23:23:44382 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
Collin Baker3435ba662020-10-07 18:07:09383 kFeatureOnByDefaultName));
384 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
asvitkine8423d172015-09-28 23:23:44385 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
386 EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
387 kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
Wezce49a7d2019-10-08 21:47:41388 test::ScopedFeatureList scoped_feature_list;
389 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44390
391 // Check the expected feature states for good measure.
392 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
393 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
394}
395
396TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
Arthur Sonzogni0844a992024-12-12 11:36:20397 struct TestCases {
asvitkine8423d172015-09-28 23:23:44398 const char* enable_features;
399 const char* disable_features;
400 bool expected_enable_trial_created;
401 bool expected_disable_trial_created;
Arthur Sonzogni0844a992024-12-12 11:36:20402 };
403 auto test_cases = std::to_array<TestCases>({
asvitkine8423d172015-09-28 23:23:44404 // If no enable/disable flags are specified, no trials should be created.
405 {"", "", false, false},
406 // Enabling the feature should result in the enable trial created.
407 {kFeatureOffByDefaultName, "", true, false},
408 // Disabling the feature should result in the disable trial created.
409 {"", kFeatureOffByDefaultName, false, true},
Arthur Sonzogni0844a992024-12-12 11:36:20410 });
asvitkine8423d172015-09-28 23:23:44411
412 const char kTrialName[] = "ForcingTrial";
413 const char kForcedOnGroupName[] = "ForcedOn";
414 const char kForcedOffGroupName[] = "ForcedOff";
415
Daniel Chengf45f47602022-02-28 22:38:32416 for (size_t i = 0; i < std::size(test_cases); ++i) {
asvitkine8423d172015-09-28 23:23:44417 const auto& test_case = test_cases[i];
418 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
419 test_case.enable_features,
420 test_case.disable_features));
421
Takashi Sakamoto15d4a672022-08-05 07:24:16422 test::ScopedFeatureList outer_scope;
423 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
424
Wezce49a7d2019-10-08 21:47:41425 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19426 feature_list->InitFromCommandLine(test_case.enable_features,
427 test_case.disable_features);
asvitkine8423d172015-09-28 23:23:44428
429 FieldTrial* enable_trial = nullptr;
430 if (feature_list->IsFeatureOverriddenFromCommandLine(
431 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
432 enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
433 kForcedOnGroupName);
434 feature_list->AssociateReportingFieldTrial(
435 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
436 enable_trial);
437 }
438 FieldTrial* disable_trial = nullptr;
439 if (feature_list->IsFeatureOverriddenFromCommandLine(
440 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
441 disable_trial = base::FieldTrialList::CreateFieldTrial(
442 kTrialName, kForcedOffGroupName);
443 feature_list->AssociateReportingFieldTrial(
444 kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
445 disable_trial);
446 }
447 EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
448 EXPECT_EQ(test_case.expected_disable_trial_created,
449 disable_trial != nullptr);
Wezce49a7d2019-10-08 21:47:41450 test::ScopedFeatureList scoped_feature_list;
451 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine8423d172015-09-28 23:23:44452
453 EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
454 if (disable_trial) {
455 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
456 EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
457 EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
458 } else if (enable_trial) {
459 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
460 EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
461 EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
462 }
463 }
464}
465
Alexei Svitkinef3d64cae2024-11-20 19:55:56466TEST_F(FeatureListTest, RegisterExtraFeatureOverrides_ReplaceUseDefault) {
467 auto feature_list = std::make_unique<FeatureList>();
468
469 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Trial1", "Group");
470 feature_list->RegisterFieldTrialOverride(
471 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
472
473 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Trial2", "Group");
474 feature_list->RegisterFieldTrialOverride(
475 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
476
477 std::vector<FeatureList::FeatureOverrideInfo> overrides;
478 overrides.emplace_back(std::cref(kFeatureOnByDefault),
479 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
480 overrides.emplace_back(std::cref(kFeatureOffByDefault),
481 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
482 feature_list->RegisterExtraFeatureOverrides(
483 std::move(overrides), /*replace_use_default_overrides=*/true);
484 test::ScopedFeatureList scoped_feature_list;
485 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
486
487 // OVERRIDE_USE_DEFAULT entries should be overridden by AwFeatureOverrides.
488 // Before querying the feature, the trials shouldn't be active, but should
489 // be activated after querying.
490
491 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("Trial1"));
492 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
493 EXPECT_TRUE(base::FieldTrialList::IsTrialActive("Trial1"));
494
495 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("Trial2"));
496 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
497 EXPECT_TRUE(base::FieldTrialList::IsTrialActive("Trial2"));
498}
499
Lily Chend49e3752019-08-09 19:05:24500TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
Lily Chend49e3752019-08-09 19:05:24501 auto feature_list = std::make_unique<FeatureList>();
502 std::vector<FeatureList::FeatureOverrideInfo> overrides;
Alexei Svitkinef3d64cae2024-11-20 19:55:56503 overrides.emplace_back(std::cref(kFeatureOnByDefault),
504 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
505 overrides.emplace_back(std::cref(kFeatureOffByDefault),
506 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
Lily Chend49e3752019-08-09 19:05:24507 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
Wezce49a7d2019-10-08 21:47:41508 test::ScopedFeatureList scoped_feature_list;
509 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Lily Chend49e3752019-08-09 19:05:24510
511 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
512 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
513}
514
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19515TEST_F(FeatureListTest, InitFromCommandLineThenRegisterExtraOverrides) {
Lily Chend49e3752019-08-09 19:05:24516 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19517 feature_list->InitFromCommandLine(kFeatureOnByDefaultName,
518 kFeatureOffByDefaultName);
Lily Chend49e3752019-08-09 19:05:24519 std::vector<FeatureList::FeatureOverrideInfo> overrides;
Alexei Svitkinef3d64cae2024-11-20 19:55:56520 overrides.emplace_back(std::cref(kFeatureOnByDefault),
521 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
522 overrides.emplace_back(std::cref(kFeatureOffByDefault),
523 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
Lily Chend49e3752019-08-09 19:05:24524 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
Wezce49a7d2019-10-08 21:47:41525 test::ScopedFeatureList scoped_feature_list;
526 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
Lily Chend49e3752019-08-09 19:05:24527
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19528 // The InitFromCommandLine supersedes the RegisterExtraFeatureOverrides
Lily Chend49e3752019-08-09 19:05:24529 // because it was called first.
530 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
531 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
532
533 std::string enable_features;
534 std::string disable_features;
535 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
536 &disable_features);
537 EXPECT_EQ(kFeatureOnByDefaultName, SortFeatureListString(enable_features));
538 EXPECT_EQ(kFeatureOffByDefaultName, SortFeatureListString(disable_features));
539}
540
asvitkine86340192015-12-01 00:45:29541TEST_F(FeatureListTest, GetFeatureOverrides) {
Wezce49a7d2019-10-08 21:47:41542 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19543 feature_list->InitFromCommandLine("A,X", "D");
asvitkine86340192015-12-01 00:45:29544
Daniel Cheng2628f682024-05-03 16:18:45545 static BASE_FEATURE(feature_b, "B", FEATURE_ENABLED_BY_DEFAULT);
546 static BASE_FEATURE(feature_c, "C", FEATURE_DISABLED_BY_DEFAULT);
Lily Chend49e3752019-08-09 19:05:24547 std::vector<FeatureList::FeatureOverrideInfo> overrides;
Alexei Svitkinef3d64cae2024-11-20 19:55:56548 overrides.emplace_back(std::cref(feature_b),
549 FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
550 overrides.emplace_back(std::cref(feature_c),
551 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
Lily Chend49e3752019-08-09 19:05:24552 feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
553
asvitkine86340192015-12-01 00:45:29554 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
Peter Kasting134ef9af2024-12-28 02:30:09555 feature_list->RegisterFieldTrialOverride(
556 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
asvitkine86340192015-12-01 00:45:29557
Wezce49a7d2019-10-08 21:47:41558 test::ScopedFeatureList scoped_feature_list;
559 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine86340192015-12-01 00:45:29560
561 std::string enable_features;
562 std::string disable_features;
563 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
564 &disable_features);
Lily Chend49e3752019-08-09 19:05:24565 EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
566 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
Alexei Svitkine223d2282018-02-08 00:18:35567
568 FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
569 &disable_features);
Lily Chend49e3752019-08-09 19:05:24570 EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
571 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
asvitkine86340192015-12-01 00:45:29572}
573
asvitkine6d31c52e2016-03-22 15:37:52574TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
Wezce49a7d2019-10-08 21:47:41575 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19576 feature_list->InitFromCommandLine("A,X", "D");
asvitkine6d31c52e2016-03-22 15:37:52577
578 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
579 feature_list->RegisterFieldTrialOverride(
580 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
581
Wezce49a7d2019-10-08 21:47:41582 test::ScopedFeatureList scoped_feature_list;
583 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine6d31c52e2016-03-22 15:37:52584
585 std::string enable_features;
586 std::string disable_features;
587 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
588 &disable_features);
589 EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
590 EXPECT_EQ("D", SortFeatureListString(disable_features));
591}
592
jwd07b90382016-05-06 20:39:42593TEST_F(FeatureListTest, GetFieldTrial) {
jwd07b90382016-05-06 20:39:42594 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
Wezce49a7d2019-10-08 21:47:41595 auto feature_list = std::make_unique<FeatureList>();
jwd07b90382016-05-06 20:39:42596 feature_list->RegisterFieldTrialOverride(
597 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
Wezce49a7d2019-10-08 21:47:41598 test::ScopedFeatureList scoped_feature_list;
599 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
jwd07b90382016-05-06 20:39:42600
601 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
602 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
603}
604
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19605TEST_F(FeatureListTest, InitFromCommandLine_WithFieldTrials) {
asvitkineb2e44d82015-12-01 04:10:28606 FieldTrialList::CreateFieldTrial("Trial", "Group");
Wezce49a7d2019-10-08 21:47:41607 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19608 feature_list->InitFromCommandLine("A,OffByDefault<Trial,X", "D");
Wezce49a7d2019-10-08 21:47:41609 test::ScopedFeatureList scoped_feature_list;
610 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkineb2e44d82015-12-01 04:10:28611
612 EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
613 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
614 EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
615}
616
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19617TEST_F(FeatureListTest, InitFromCommandLine_UseDefault) {
asvitkine6d31c52e2016-03-22 15:37:52618 FieldTrialList::CreateFieldTrial("T1", "Group");
619 FieldTrialList::CreateFieldTrial("T2", "Group");
Wezce49a7d2019-10-08 21:47:41620 auto feature_list = std::make_unique<FeatureList>();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19621 feature_list->InitFromCommandLine("A,*OffByDefault<T1,*OnByDefault<T2,X",
622 "D");
Wezce49a7d2019-10-08 21:47:41623 test::ScopedFeatureList scoped_feature_list;
624 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
asvitkine6d31c52e2016-03-22 15:37:52625
626 EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
627 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
628 EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
629
630 EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
631 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
632 EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
633}
634
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19635TEST_F(FeatureListTest, InitInstance) {
dcheng093de9b2016-04-04 21:25:51636 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Wezce49a7d2019-10-08 21:47:41637 test::ScopedFeatureList scoped_feature_list;
638 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
639
changwan5b9da192016-03-31 07:36:19640 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
641 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
642
643 // Initialize from command line if we haven't yet.
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19644 FeatureList::InitInstance("", kFeatureOnByDefaultName);
changwan5b9da192016-03-31 07:36:19645 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
646 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
647
648 // Do not initialize from commandline if we have already.
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19649 FeatureList::InitInstance(kFeatureOffByDefaultName, "");
changwan5b9da192016-03-31 07:36:19650 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
651 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
652}
653
joedow958f0472016-07-07 22:08:55654TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
Wezce49a7d2019-10-08 21:47:41655 std::unique_ptr<FeatureList> original_feature_list =
656 FeatureList::ClearInstanceForTesting();
657
joedow958f0472016-07-07 22:08:55658 // This test case simulates the calling pattern found in code which does not
659 // explicitly initialize the features list.
660 // All IsEnabled() calls should return the default value in this scenario.
661 EXPECT_EQ(nullptr, FeatureList::GetInstance());
662 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
663 EXPECT_EQ(nullptr, FeatureList::GetInstance());
664 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
Wezce49a7d2019-10-08 21:47:41665
Peter Kasting134ef9af2024-12-28 02:30:09666 if (original_feature_list) {
Wezce49a7d2019-10-08 21:47:41667 FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
Peter Kasting134ef9af2024-12-28 02:30:09668 }
joedow958f0472016-07-07 22:08:55669}
670
lawrencewu5e03cd32016-12-05 16:23:28671TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {
672 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
673
674 // Create some overrides.
675 feature_list->RegisterOverride(kFeatureOffByDefaultName,
676 FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
677 feature_list->RegisterOverride(
678 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
679 feature_list->FinalizeInitialization();
680
681 // Create an allocator and store the overrides.
Alexandr Ilin027ca3d32019-02-12 18:37:33682 base::MappedReadOnlyRegion shm =
683 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
684 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
685 "");
lawrencewu5e03cd32016-12-05 16:23:28686 feature_list->AddFeaturesToAllocator(&allocator);
687
688 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
689
690 // Check that the new feature list is empty.
691 EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
692 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
693 EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
694 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
695
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19696 feature_list2->InitFromSharedMemory(&allocator);
lawrencewu5e03cd32016-12-05 16:23:28697 // Check that the new feature list now has 2 overrides.
698 EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
699 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
700 EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
701 kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
702}
703
704TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
lawrencewu5e03cd32016-12-05 16:23:28705 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
706
707 // Create some overrides.
708 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
709 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
710 feature_list->RegisterFieldTrialOverride(
711 kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
712 feature_list->RegisterFieldTrialOverride(
713 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
714 feature_list->FinalizeInitialization();
715
716 // Create an allocator and store the overrides.
Alexandr Ilin027ca3d32019-02-12 18:37:33717 base::MappedReadOnlyRegion shm =
718 base::ReadOnlySharedMemoryRegion::Create(4 << 10);
719 WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
720 "");
lawrencewu5e03cd32016-12-05 16:23:28721 feature_list->AddFeaturesToAllocator(&allocator);
722
723 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19724 feature_list2->InitFromSharedMemory(&allocator);
lawrencewu5e03cd32016-12-05 16:23:28725 feature_list2->FinalizeInitialization();
726
727 // Check that the field trials are still associated.
728 FieldTrial* associated_trial1 =
729 feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
730 FieldTrial* associated_trial2 =
731 feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
732 EXPECT_EQ(associated_trial1, trial1);
733 EXPECT_EQ(associated_trial2, trial2);
734}
735
Marijn Kruisselbrink1934df72023-12-04 22:30:55736TEST_F(FeatureListTest, SetEarlyAccessInstance_AllowList) {
737 test::ScopedFeatureList clear_feature_list;
738 clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
739
740 auto early_access_feature_list = std::make_unique<FeatureList>();
741 early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault");
742 FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list),
Marijn Kruisselbrink0b6d5df2023-12-14 22:31:29743 {"DcheckIsFatal", "OnByDefault"});
Marijn Kruisselbrink1934df72023-12-04 22:30:55744 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
745 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
746 EXPECT_EQ(&kFeatureOffByDefault,
747 FeatureList::GetEarlyAccessedFeatureForTesting());
748 FeatureList::ResetEarlyFeatureAccessTrackerForTesting();
749}
750
751TEST_F(FeatureListTest, SetEarlyAccessInstance_ReplaceByRealList) {
752 test::ScopedFeatureList clear_feature_list;
753 clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
754
755 auto early_access_feature_list = std::make_unique<FeatureList>();
756 early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault");
Marijn Kruisselbrink0b6d5df2023-12-14 22:31:29757 FeatureList::SetEarlyAccessInstance(
758 std::move(early_access_feature_list),
759 {"DcheckIsFatal", "OffByDefault", "OnByDefault"});
Marijn Kruisselbrink1934df72023-12-04 22:30:55760 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
761 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
762
763 auto feature_list = std::make_unique<FeatureList>();
764 feature_list->InitFromCommandLine("", "");
765 FeatureList::SetInstance(std::move(feature_list));
766 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
767 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
768}
769
Miriam Zimmermanb4683c12021-12-01 15:44:33770#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
771 defined(GTEST_HAS_DEATH_TEST)
772using FeatureListDeathTest = FeatureListTest;
773TEST_F(FeatureListDeathTest, DiesWithBadFeatureName) {
Daniel Cheng2628f682024-05-03 16:18:45774 // TODO(dcheng): Add a nocompile version of this test. In general, people
775 // should not be constructing features at runtime anyway but just in case...
Miriam Zimmermanb4683c12021-12-01 15:44:33776 EXPECT_DEATH(
777 Feature(
778 StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX), "MyFeature"}).c_str(),
Daniel Cheng2628f682024-05-03 16:18:45779 FEATURE_DISABLED_BY_DEFAULT,
780 internal::FeatureMacroHandshake::kSecret),
Miriam Zimmermanb4683c12021-12-01 15:44:33781 StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
782 "MyFeature"}));
783}
784#endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) &&
785 // defined(GTEST_HAS_DEATH_TEST)
786
Miriam Zimmermandfe28072021-11-22 22:16:31787TEST(FeatureListAccessorTest, DefaultStates) {
Tom Sepezc0c75bee2022-12-16 03:12:38788 test::ScopedFeatureList scoped_feature_list;
Miriam Zimmermandfe28072021-11-22 22:16:31789 auto feature_list = std::make_unique<FeatureList>();
790 auto feature_list_accessor = feature_list->ConstructAccessor();
Miriam Zimmermandfe28072021-11-22 22:16:31791 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
792
793 EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
794 kFeatureOnByDefault.name),
795 FeatureList::OVERRIDE_USE_DEFAULT);
796 EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
797 kFeatureOffByDefault.name),
798 FeatureList::OVERRIDE_USE_DEFAULT);
799}
800
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19801TEST(FeatureListAccessorTest, InitFromCommandLine) {
Arthur Sonzogni0844a992024-12-12 11:36:20802 struct TestCases {
Miriam Zimmermandfe28072021-11-22 22:16:31803 const char* enable_features;
804 const char* disable_features;
805 FeatureList::OverrideState expected_feature_on_state;
806 FeatureList::OverrideState expected_feature_off_state;
Arthur Sonzogni0844a992024-12-12 11:36:20807 };
808 auto test_cases = std::to_array<TestCases>({
Miriam Zimmermandfe28072021-11-22 22:16:31809 {"", "", FeatureList::OVERRIDE_USE_DEFAULT,
810 FeatureList::OVERRIDE_USE_DEFAULT},
811 {"OffByDefault", "", FeatureList::OVERRIDE_USE_DEFAULT,
812 FeatureList::OVERRIDE_ENABLE_FEATURE},
813 {"OffByDefault", "OnByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
814 FeatureList::OVERRIDE_ENABLE_FEATURE},
815 {"OnByDefault,OffByDefault", "", FeatureList::OVERRIDE_ENABLE_FEATURE,
816 FeatureList::OVERRIDE_ENABLE_FEATURE},
817 {"", "OnByDefault,OffByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
818 FeatureList::OVERRIDE_DISABLE_FEATURE},
819 // In the case an entry is both, disable takes precedence.
820 {"OnByDefault", "OnByDefault,OffByDefault",
821 FeatureList::OVERRIDE_DISABLE_FEATURE,
822 FeatureList::OVERRIDE_DISABLE_FEATURE},
Arthur Sonzogni0844a992024-12-12 11:36:20823 });
Miriam Zimmermandfe28072021-11-22 22:16:31824
Daniel Chengf45f47602022-02-28 22:38:32825 for (size_t i = 0; i < std::size(test_cases); ++i) {
Miriam Zimmermandfe28072021-11-22 22:16:31826 const auto& test_case = test_cases[i];
827 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
828 test_case.enable_features,
829 test_case.disable_features));
830
Tom Sepezc0c75bee2022-12-16 03:12:38831 test::ScopedFeatureList scoped_feature_list;
Miriam Zimmermandfe28072021-11-22 22:16:31832 auto feature_list = std::make_unique<FeatureList>();
833 auto feature_list_accessor = feature_list->ConstructAccessor();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19834 feature_list->InitFromCommandLine(test_case.enable_features,
835 test_case.disable_features);
Miriam Zimmermandfe28072021-11-22 22:16:31836 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
837
838 EXPECT_EQ(test_case.expected_feature_on_state,
839 feature_list_accessor->GetOverrideStateByFeatureName(
840 kFeatureOnByDefault.name))
841 << i;
842 EXPECT_EQ(test_case.expected_feature_off_state,
843 feature_list_accessor->GetOverrideStateByFeatureName(
844 kFeatureOffByDefault.name))
845 << i;
846 }
847}
848
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19849TEST(FeatureListAccessorTest, InitFromCommandLineWithFeatureParams) {
Arthur Sonzogni0844a992024-12-12 11:36:20850 struct TestCases {
Miriam Zimmerman79f6cac2022-06-17 17:58:25851 const std::string enable_features;
852 const std::map<std::string, std::string> expected_feature_params;
Arthur Sonzogni0844a992024-12-12 11:36:20853 };
854 auto test_cases = std::to_array<TestCases>({
Miriam Zimmerman79f6cac2022-06-17 17:58:25855 {"Feature:x/100/y/test", {{"x", "100"}, {"y", "test"}}},
856 {"Feature<Trial:asdf/ghjkl/y/123", {{"asdf", "ghjkl"}, {"y", "123"}}},
Arthur Sonzogni0844a992024-12-12 11:36:20857 });
Miriam Zimmerman79f6cac2022-06-17 17:58:25858
859 // Clear global state so that repeated runs of this test don't flake.
860 // When https://crrev.com/c/3694674 is submitted, we should be able to remove
861 // this.
862 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
863
864 for (size_t i = 0; i < std::size(test_cases); ++i) {
865 const auto& test_case = test_cases[i];
866 SCOPED_TRACE(test_case.enable_features);
867
Tom Sepezc0c75bee2022-12-16 03:12:38868 test::ScopedFeatureList scoped_feature_list;
Miriam Zimmerman79f6cac2022-06-17 17:58:25869 auto feature_list = std::make_unique<FeatureList>();
870 auto feature_list_accessor = feature_list->ConstructAccessor();
Gabriel Gauthier-Shalom89627a67a2023-11-29 22:11:19871 feature_list->InitFromCommandLine(test_case.enable_features, "");
Miriam Zimmerman79f6cac2022-06-17 17:58:25872 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
873
874 EXPECT_EQ(FeatureList::OVERRIDE_ENABLE_FEATURE,
875 feature_list_accessor->GetOverrideStateByFeatureName("Feature"))
876 << i;
877 std::map<std::string, std::string> actual_params;
878 EXPECT_TRUE(feature_list_accessor->GetParamsByFeatureName("Feature",
879 &actual_params))
880 << i;
881 EXPECT_EQ(test_case.expected_feature_params, actual_params) << i;
882 }
883}
884
Kendrake Tsuid3895ec2024-01-22 22:08:39885// Test only class to verify correctness of
886// FeatureList::VisitFeaturesAndParams().
887class TestFeatureVisitor : public FeatureVisitor {
888 public:
889 TestFeatureVisitor() = default;
890
891 TestFeatureVisitor(const TestFeatureVisitor&) = delete;
892 TestFeatureVisitor& operator=(const TestFeatureVisitor&) = delete;
893
894 ~TestFeatureVisitor() override = default;
895
896 struct VisitedFeatureState {
897 auto operator<=>(const VisitedFeatureState&) const = default;
898
899 std::string feature_name;
900 const base::FeatureList::OverrideState override_state;
901 base::FieldTrialParams params;
902 std::string trial_name;
903 std::string group_name;
904 };
905
906 void Visit(const std::string& feature_name,
907 FeatureList::OverrideState override_state,
908 const FieldTrialParams& params,
909 const std::string& trial_name,
910 const std::string& group_name) override {
911 feature_state_.insert(TestFeatureVisitor::VisitedFeatureState{
912 feature_name, override_state, params, trial_name, group_name});
913 }
914
915 const std::multiset<TestFeatureVisitor::VisitedFeatureState>&
916 feature_state() {
917 return feature_state_;
918 }
919
920 private:
921 std::multiset<VisitedFeatureState> feature_state_;
922};
923
924// Makes test output human readable.
925std::ostream& operator<<(std::ostream& out,
926 const TestFeatureVisitor::VisitedFeatureState& state) {
927 out << ".feature_name='" << state.feature_name
928 << "', .override_state=" << state.override_state << ", .params={";
929
930 for (const auto& param : state.params) {
931 out << param.first << "=" << param.second << ", ";
932 }
933
934 out << "}, .trial_name='" << state.trial_name << "', .group_name='"
935 << state.group_name << "'";
936 return out;
937}
938
939TEST(TestFeatureVisitor, FeatureWithNoFieldTrial) {
940 base::test::ScopedFeatureList outer_scope;
941 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
942
943 base::test::ScopedFeatureList feature_list;
944 feature_list.InitWithFeatures(/*enabled_features=*/{kFeatureOffByDefault},
945 /*disabled_features=*/{kFeatureOnByDefault});
946
947 TestFeatureVisitor visitor;
948 base::FeatureList::VisitFeaturesAndParams(visitor);
949 std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
950 visitor.feature_state();
951
952 std::multiset<TestFeatureVisitor::VisitedFeatureState>
953 expected_feature_state = {
954 {"OnByDefault", FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
955 FieldTrialParams{}, "", ""},
956 {"OffByDefault", FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
957 FieldTrialParams{}, "", ""},
958 };
959
960 EXPECT_EQ(actual_feature_state, expected_feature_state);
961}
962
963TEST(TestFeatureVisitor, FeatureOverrideUseDefault) {
964 base::test::ScopedFeatureList outer_scope;
965 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
966
967 auto feature_list = std::make_unique<base::FeatureList>();
968 base::FieldTrial* trial =
969 base::FieldTrialList::CreateFieldTrial("TrialExample", "A");
970 feature_list->RegisterFieldTrialOverride(
971 "TestFeature", base::FeatureList::OVERRIDE_USE_DEFAULT, trial);
972
973 base::test::ScopedFeatureList initialized_feature_list;
974 initialized_feature_list.InitWithFeatureList(std::move(feature_list));
975
976 TestFeatureVisitor visitor;
977 base::FeatureList::VisitFeaturesAndParams(visitor);
978 std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
979 visitor.feature_state();
980
981 std::multiset<TestFeatureVisitor::VisitedFeatureState>
982 expected_feature_state = {
983 {"TestFeature", FeatureList::OverrideState::OVERRIDE_USE_DEFAULT,
984 FieldTrialParams{}, "TrialExample", "A"}};
985
986 EXPECT_EQ(actual_feature_state, expected_feature_state);
987}
988
989TEST(TestFeatureVisitor, FeatureHasParams) {
990 base::test::ScopedFeatureList outer_scope;
991 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
992
993 base::test::ScopedFeatureList initialized_feature_list;
994
995 initialized_feature_list.InitFromCommandLine(
Peter Kasting811504a72025-01-09 03:18:50996 /*enable_features=*/"TestFeature<foo.bar:k1/v1/k2/v2",
997 /*disable_features=*/"");
Kendrake Tsuid3895ec2024-01-22 22:08:39998
999 TestFeatureVisitor visitor;
1000 base::FeatureList::VisitFeaturesAndParams(visitor);
1001 std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
1002 visitor.feature_state();
1003
1004 std::multiset<TestFeatureVisitor::VisitedFeatureState>
1005 expected_feature_state = {
1006 {"TestFeature", FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
1007 FieldTrialParams{{"k1", "v1"}, {"k2", "v2"}}, "foo", "bar"},
1008 };
1009
1010 EXPECT_EQ(actual_feature_state, expected_feature_state);
1011}
Leszek Swirskif7f53b432024-09-30 10:12:101012
1013TEST(TestFeatureVisitor, FeatureWithPrefix) {
1014 base::test::ScopedFeatureList outer_scope;
1015 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
1016
1017 base::test::ScopedFeatureList initialized_feature_list;
1018
1019 initialized_feature_list.InitFromCommandLine(
1020 /*enable_features=*/
1021 "AFeature,AnotherFeature,TestFeature,TestFeature2,PrefixedFeature,"
1022 "PrefixedFeature2",
1023 /*disable_features=*/"");
1024
1025 TestFeatureVisitor visitor;
1026 base::FeatureList::VisitFeaturesAndParams(visitor, "Prefixed");
1027 std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
1028 visitor.feature_state();
1029
1030 std::multiset<TestFeatureVisitor::VisitedFeatureState>
1031 expected_feature_state = {
1032 {"PrefixedFeature",
1033 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
1034 FieldTrialParams{}, "", ""},
1035 {"PrefixedFeature2",
1036 FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
1037 FieldTrialParams{}, "", ""},
1038 };
1039
1040 EXPECT_EQ(actual_feature_state, expected_feature_state);
1041}
Kendrake Tsuid3895ec2024-01-22 22:08:391042
asvitkinebccbb862015-09-04 17:17:451043} // namespace base