1 // Copyright 2017 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/test/scoped_feature_list.h"
6 
7 #include <map>
8 #include <string>
9 #include <utility>
10 
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/field_trial_params.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace base {
16 namespace test {
17 
18 namespace {
19 
20 const Feature kTestFeature1{"TestFeature1", FEATURE_DISABLED_BY_DEFAULT};
21 const Feature kTestFeature2{"TestFeature2", FEATURE_DISABLED_BY_DEFAULT};
22 
ExpectFeatures(const std::string & enabled_features,const std::string & disabled_features)23 void ExpectFeatures(const std::string& enabled_features,
24                     const std::string& disabled_features) {
25   FeatureList* list = FeatureList::GetInstance();
26   std::string actual_enabled_features;
27   std::string actual_disabled_features;
28 
29   list->GetFeatureOverrides(&actual_enabled_features,
30                             &actual_disabled_features);
31 
32   EXPECT_EQ(enabled_features, actual_enabled_features);
33   EXPECT_EQ(disabled_features, actual_disabled_features);
34 }
35 
36 }  // namespace
37 
38 class ScopedFeatureListTest : public testing::Test {
39  public:
ScopedFeatureListTest()40   ScopedFeatureListTest() {
41     // Clear default feature list.
42     std::unique_ptr<FeatureList> feature_list(new FeatureList);
43     feature_list->InitializeFromCommandLine(std::string(), std::string());
44     original_feature_list_ = FeatureList::ClearInstanceForTesting();
45     FeatureList::SetInstance(std::move(feature_list));
46   }
47 
~ScopedFeatureListTest()48   ~ScopedFeatureListTest() override {
49     // Restore feature list.
50     if (original_feature_list_) {
51       FeatureList::ClearInstanceForTesting();
52       FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_));
53     }
54   }
55 
56  private:
57   // Save the present FeatureList and restore it after test finish.
58   std::unique_ptr<FeatureList> original_feature_list_;
59 
60   DISALLOW_COPY_AND_ASSIGN(ScopedFeatureListTest);
61 };
62 
TEST_F(ScopedFeatureListTest,BasicScoped)63 TEST_F(ScopedFeatureListTest, BasicScoped) {
64   ExpectFeatures(std::string(), std::string());
65   EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
66   {
67     test::ScopedFeatureList feature_list1;
68     feature_list1.InitFromCommandLine("TestFeature1", std::string());
69     ExpectFeatures("TestFeature1", std::string());
70     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
71   }
72   ExpectFeatures(std::string(), std::string());
73   EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
74 }
75 
TEST_F(ScopedFeatureListTest,EnableWithFeatureParameters)76 TEST_F(ScopedFeatureListTest, EnableWithFeatureParameters) {
77   const char kParam1[] = "param_1";
78   const char kParam2[] = "param_2";
79   const char kValue1[] = "value_1";
80   const char kValue2[] = "value_2";
81   std::map<std::string, std::string> parameters;
82   parameters[kParam1] = kValue1;
83   parameters[kParam2] = kValue2;
84 
85   ExpectFeatures(std::string(), std::string());
86   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
87   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
88   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
89   FieldTrial::ActiveGroups active_groups;
90   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
91   EXPECT_EQ(0u, active_groups.size());
92 
93   {
94     test::ScopedFeatureList feature_list;
95 
96     feature_list.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
97     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
98     EXPECT_EQ(kValue1,
99               GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
100     EXPECT_EQ(kValue2,
101               GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
102     active_groups.clear();
103     FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
104     EXPECT_EQ(1u, active_groups.size());
105   }
106 
107   ExpectFeatures(std::string(), std::string());
108   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
109   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
110   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
111   active_groups.clear();
112   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
113   EXPECT_EQ(0u, active_groups.size());
114 }
115 
TEST_F(ScopedFeatureListTest,OverrideWithFeatureParameters)116 TEST_F(ScopedFeatureListTest, OverrideWithFeatureParameters) {
117   FieldTrialList field_trial_list(nullptr);
118   scoped_refptr<FieldTrial> trial =
119       FieldTrialList::CreateFieldTrial("foo", "bar");
120   const char kParam[] = "param_1";
121   const char kValue[] = "value_1";
122   std::map<std::string, std::string> parameters;
123   parameters[kParam] = kValue;
124 
125   test::ScopedFeatureList feature_list1;
126   feature_list1.InitFromCommandLine("TestFeature1<foo,TestFeature2",
127                                     std::string());
128 
129   // Check initial state.
130   ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
131   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
132   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
133   EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
134   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
135   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
136   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
137 
138   {
139     // Override feature with existing field trial.
140     test::ScopedFeatureList feature_list2;
141 
142     feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
143     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
144     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
145     EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
146     EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
147     EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
148     EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
149     EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
150   }
151 
152   // Check that initial state is restored.
153   ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
154   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
155   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
156   EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
157   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
158   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
159   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
160 
161   {
162     // Override feature with no existing field trial.
163     test::ScopedFeatureList feature_list2;
164 
165     feature_list2.InitAndEnableFeatureWithParameters(kTestFeature2, parameters);
166     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
167     EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
168     EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
169     EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
170     EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
171     EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
172   }
173 
174   // Check that initial state is restored.
175   ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
176   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
177   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
178   EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
179   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
180   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
181   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
182 }
183 
TEST_F(ScopedFeatureListTest,EnableFeatureOverrideDisable)184 TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) {
185   test::ScopedFeatureList feature_list1;
186   feature_list1.InitWithFeatures({}, {kTestFeature1});
187 
188   {
189     test::ScopedFeatureList feature_list2;
190     feature_list2.InitWithFeatures({kTestFeature1}, {});
191     ExpectFeatures("TestFeature1", std::string());
192   }
193 }
194 
TEST_F(ScopedFeatureListTest,FeatureOverrideNotMakeDuplicate)195 TEST_F(ScopedFeatureListTest, FeatureOverrideNotMakeDuplicate) {
196   test::ScopedFeatureList feature_list1;
197   feature_list1.InitWithFeatures({}, {kTestFeature1});
198 
199   {
200     test::ScopedFeatureList feature_list2;
201     feature_list2.InitWithFeatures({}, {kTestFeature1});
202     ExpectFeatures(std::string(), "TestFeature1");
203   }
204 }
205 
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDefault)206 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault) {
207   test::ScopedFeatureList feature_list1;
208   feature_list1.InitFromCommandLine("*TestFeature1", std::string());
209 
210   {
211     test::ScopedFeatureList feature_list2;
212     feature_list2.InitWithFeatures({kTestFeature1}, {});
213     ExpectFeatures("TestFeature1", std::string());
214   }
215 }
216 
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDefault2)217 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault2) {
218   test::ScopedFeatureList feature_list1;
219   feature_list1.InitFromCommandLine("*TestFeature1", std::string());
220 
221   {
222     test::ScopedFeatureList feature_list2;
223     feature_list2.InitWithFeatures({}, {kTestFeature1});
224     ExpectFeatures(std::string(), "TestFeature1");
225   }
226 }
227 
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithEnabledFieldTrial)228 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithEnabledFieldTrial) {
229   test::ScopedFeatureList feature_list1;
230 
231   std::unique_ptr<FeatureList> feature_list(new FeatureList);
232   FieldTrialList field_trial_list(nullptr);
233   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
234   feature_list->RegisterFieldTrialOverride(
235       kTestFeature1.name, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
236   feature_list1.InitWithFeatureList(std::move(feature_list));
237 
238   {
239     test::ScopedFeatureList feature_list2;
240     feature_list2.InitWithFeatures({kTestFeature1}, {});
241     ExpectFeatures("TestFeature1", std::string());
242   }
243 }
244 
TEST_F(ScopedFeatureListTest,FeatureOverrideFeatureWithDisabledFieldTrial)245 TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDisabledFieldTrial) {
246   test::ScopedFeatureList feature_list1;
247 
248   std::unique_ptr<FeatureList> feature_list(new FeatureList);
249   FieldTrialList field_trial_list(nullptr);
250   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
251   feature_list->RegisterFieldTrialOverride(
252       kTestFeature1.name, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
253   feature_list1.InitWithFeatureList(std::move(feature_list));
254 
255   {
256     test::ScopedFeatureList feature_list2;
257     feature_list2.InitWithFeatures({kTestFeature1}, {});
258     ExpectFeatures("TestFeature1", std::string());
259   }
260 }
261 
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingFeature)262 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature) {
263   test::ScopedFeatureList feature_list1;
264   feature_list1.InitWithFeatures({}, {kTestFeature1});
265 
266   {
267     test::ScopedFeatureList feature_list2;
268     feature_list2.InitWithFeatures({}, {kTestFeature2});
269     EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
270     EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
271   }
272 }
273 
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingFeature2)274 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature2) {
275   test::ScopedFeatureList feature_list1;
276   feature_list1.InitWithFeatures({}, {kTestFeature1});
277 
278   {
279     test::ScopedFeatureList feature_list2;
280     feature_list2.InitWithFeatures({kTestFeature2}, {});
281     ExpectFeatures("TestFeature2", "TestFeature1");
282   }
283 }
284 
TEST_F(ScopedFeatureListTest,FeatureOverrideKeepsOtherExistingDefaultFeature)285 TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingDefaultFeature) {
286   test::ScopedFeatureList feature_list1;
287   feature_list1.InitFromCommandLine("*TestFeature1", std::string());
288 
289   {
290     test::ScopedFeatureList feature_list2;
291     feature_list2.InitWithFeatures({}, {kTestFeature2});
292     ExpectFeatures("*TestFeature1", "TestFeature2");
293   }
294 }
295 
TEST_F(ScopedFeatureListTest,ScopedFeatureListIsNoopWhenNotInitialized)296 TEST_F(ScopedFeatureListTest, ScopedFeatureListIsNoopWhenNotInitialized) {
297   test::ScopedFeatureList feature_list1;
298   feature_list1.InitFromCommandLine("*TestFeature1", std::string());
299 
300   // A ScopedFeatureList on which Init() is not called should not reset things
301   // when going out of scope.
302   { test::ScopedFeatureList feature_list2; }
303 
304   ExpectFeatures("*TestFeature1", std::string());
305 }
306 
307 }  // namespace test
308 }  // namespace base
309