xref: /aosp_15_r20/external/cronet/base/metrics/field_trial_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/metrics/field_trial.h"
6 
7 #include <stddef.h>
8 
9 #include <string_view>
10 #include <utility>
11 
12 #include "base/base_switches.h"
13 #include "base/build_time.h"
14 #include "base/command_line.h"
15 #include "base/feature_list.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/metrics/field_trial_list_including_low_anonymity.h"
18 #include "base/metrics/field_trial_param_associator.h"
19 #include "base/rand_util.h"
20 #include "base/run_loop.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/test/gtest_util.h"
24 #include "base/test/mock_entropy_provider.h"
25 #include "base/test/multiprocess_test.h"
26 #include "base/test/scoped_feature_list.h"
27 #include "base/test/task_environment.h"
28 #include "base/test/test_shared_memory_util.h"
29 #include "base/test/test_timeouts.h"
30 #include "build/build_config.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "testing/multiprocess_func_list.h"
34 
35 #if BUILDFLAG(USE_BLINK)
36 #include "base/process/launch.h"
37 #endif
38 
39 #if BUILDFLAG(IS_POSIX)
40 #include "base/files/platform_file.h"
41 #include "base/posix/global_descriptors.h"
42 #endif
43 
44 #if BUILDFLAG(IS_MAC)
45 #include "base/mac/mach_port_rendezvous.h"
46 #endif
47 
48 namespace base {
49 
50 namespace {
51 
52 // Default group name used by several tests.
53 const char kDefaultGroupName[] = "DefaultGroup";
54 
55 // Call FieldTrialList::FactoryGetFieldTrial().
CreateFieldTrial(const std::string & trial_name,int total_probability,const std::string & default_group_name,bool is_low_anonymity=false)56 scoped_refptr<FieldTrial> CreateFieldTrial(
57     const std::string& trial_name,
58     int total_probability,
59     const std::string& default_group_name,
60     bool is_low_anonymity = false) {
61   MockEntropyProvider entropy_provider(0.9);
62   return FieldTrialList::FactoryGetFieldTrial(
63       trial_name, total_probability, default_group_name, entropy_provider, 0,
64       is_low_anonymity);
65 }
66 
67 // A FieldTrialList::Observer implementation which stores the trial name and
68 // group name received via OnFieldTrialGroupFinalized() for later inspection.
69 class TestFieldTrialObserver : public FieldTrialList::Observer {
70  public:
TestFieldTrialObserver()71   TestFieldTrialObserver() { FieldTrialList::AddObserver(this); }
72   TestFieldTrialObserver(const TestFieldTrialObserver&) = delete;
73   TestFieldTrialObserver& operator=(const TestFieldTrialObserver&) = delete;
74 
~TestFieldTrialObserver()75   ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); }
76 
OnFieldTrialGroupFinalized(const FieldTrial & trial,const std::string & group)77   void OnFieldTrialGroupFinalized(const FieldTrial& trial,
78                                   const std::string& group) override {
79     trial_name_ = trial.trial_name();
80     group_name_ = group;
81   }
82 
trial_name() const83   const std::string& trial_name() const { return trial_name_; }
group_name() const84   const std::string& group_name() const { return group_name_; }
85 
86  private:
87   std::string trial_name_;
88   std::string group_name_;
89 };
90 
91 // A FieldTrialList::Observer implementation which accesses the group of a
92 // FieldTrial from OnFieldTrialGroupFinalized(). Used to test reentrancy.
93 class FieldTrialObserverAccessingGroup : public FieldTrialList::Observer {
94  public:
95   // |trial_to_access| is the FieldTrial on which to invoke Activate() when
96   // receiving an OnFieldTrialGroupFinalized() notification.
FieldTrialObserverAccessingGroup(scoped_refptr<FieldTrial> trial_to_access)97   explicit FieldTrialObserverAccessingGroup(
98       scoped_refptr<FieldTrial> trial_to_access)
99       : trial_to_access_(trial_to_access) {
100     FieldTrialList::AddObserver(this);
101   }
102   FieldTrialObserverAccessingGroup(const FieldTrialObserverAccessingGroup&) =
103       delete;
104   FieldTrialObserverAccessingGroup& operator=(
105       const FieldTrialObserverAccessingGroup&) = delete;
106 
~FieldTrialObserverAccessingGroup()107   ~FieldTrialObserverAccessingGroup() override {
108     FieldTrialList::RemoveObserver(this);
109   }
110 
OnFieldTrialGroupFinalized(const base::FieldTrial & trial,const std::string & group)111   void OnFieldTrialGroupFinalized(const base::FieldTrial& trial,
112                                   const std::string& group) override {
113     trial_to_access_->Activate();
114   }
115 
116  private:
117   scoped_refptr<FieldTrial> trial_to_access_;
118 };
119 
MockEscapeQueryParamValue(const std::string & input)120 std::string MockEscapeQueryParamValue(const std::string& input) {
121   return input;
122 }
123 
124 }  // namespace
125 
126 // Same as |TestFieldTrialObserver|, but registers for low anonymity field
127 // trials too.
128 class TestFieldTrialObserverIncludingLowAnonymity
129     : public FieldTrialList::Observer {
130  public:
TestFieldTrialObserverIncludingLowAnonymity()131   TestFieldTrialObserverIncludingLowAnonymity() {
132     FieldTrialListIncludingLowAnonymity::AddObserver(this);
133   }
134   TestFieldTrialObserverIncludingLowAnonymity(
135       const TestFieldTrialObserverIncludingLowAnonymity&) = delete;
136   TestFieldTrialObserverIncludingLowAnonymity& operator=(
137       const TestFieldTrialObserverIncludingLowAnonymity&) = delete;
138 
~TestFieldTrialObserverIncludingLowAnonymity()139   ~TestFieldTrialObserverIncludingLowAnonymity() override {
140     FieldTrialListIncludingLowAnonymity::RemoveObserver(this);
141   }
142 
OnFieldTrialGroupFinalized(const base::FieldTrial & trial,const std::string & group)143   void OnFieldTrialGroupFinalized(const base::FieldTrial& trial,
144                                   const std::string& group) override {
145     trial_name_ = trial.trial_name();
146     group_name_ = group;
147   }
148 
trial_name() const149   const std::string& trial_name() const { return trial_name_; }
group_name() const150   const std::string& group_name() const { return group_name_; }
151 
152  private:
153   std::string trial_name_;
154   std::string group_name_;
155 };
156 
157 class FieldTrialTest : public ::testing::Test {
158  public:
FieldTrialTest()159   FieldTrialTest() {
160     // The test suite instantiates a FieldTrialList but for the purpose of these
161     // tests it's cleaner to start from scratch.
162     scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
163   }
164   FieldTrialTest(const FieldTrialTest&) = delete;
165   FieldTrialTest& operator=(const FieldTrialTest&) = delete;
166 
167  private:
168   test::TaskEnvironment task_environment_;
169   test::ScopedFeatureList scoped_feature_list_;
170 };
171 
172 MATCHER(CompareActiveGroupToFieldTrial, "") {
173   const base::FieldTrial::ActiveGroup& lhs = ::testing::get<0>(arg);
174   const base::FieldTrial* rhs = ::testing::get<1>(arg).get();
175   return lhs.trial_name == rhs->trial_name() &&
176          lhs.group_name == rhs->group_name_internal();
177 }
178 
179 // Test registration, and also check that destructors are called for trials.
TEST_F(FieldTrialTest,Registration)180 TEST_F(FieldTrialTest, Registration) {
181   const char name1[] = "name 1 test";
182   const char name2[] = "name 2 test";
183   EXPECT_FALSE(FieldTrialList::Find(name1));
184   EXPECT_FALSE(FieldTrialList::Find(name2));
185 
186   scoped_refptr<FieldTrial> trial1 =
187       CreateFieldTrial(name1, 10, "default name 1 test");
188   EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
189   EXPECT_EQ(name1, trial1->trial_name());
190   EXPECT_EQ("", trial1->group_name_internal());
191 
192   trial1->AppendGroup(std::string(), 7);
193 
194   EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
195   EXPECT_FALSE(FieldTrialList::Find(name2));
196 
197   scoped_refptr<FieldTrial> trial2 =
198       CreateFieldTrial(name2, 10, "default name 2 test");
199   EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
200   EXPECT_EQ(name2, trial2->trial_name());
201   EXPECT_EQ("", trial2->group_name_internal());
202 
203   trial2->AppendGroup("a first group", 7);
204 
205   EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
206   EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
207   // Note: FieldTrialList should delete the objects at shutdown.
208 }
209 
TEST_F(FieldTrialTest,AbsoluteProbabilities)210 TEST_F(FieldTrialTest, AbsoluteProbabilities) {
211   MockEntropyProvider entropy_provider(0.51);
212   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
213       "trial name", 100, "Default", entropy_provider);
214   trial->AppendGroup("LoserA", 0);
215   trial->AppendGroup("Winner", 100);
216   trial->AppendGroup("LoserB", 0);
217   EXPECT_EQ(trial->group_name(), "Winner");
218 }
219 
TEST_F(FieldTrialTest,SmallProbabilities_49)220 TEST_F(FieldTrialTest, SmallProbabilities_49) {
221   MockEntropyProvider entropy_provider(0.49);
222   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
223       "trial name", 2, "Default", entropy_provider);
224   trial->AppendGroup("first", 1);
225   trial->AppendGroup("second", 1);
226   EXPECT_EQ(trial->group_name(), "first");
227 }
228 
TEST_F(FieldTrialTest,SmallProbabilities_51)229 TEST_F(FieldTrialTest, SmallProbabilities_51) {
230   MockEntropyProvider entropy_provider(0.51);
231   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
232       "trial name", 2, "Default", entropy_provider);
233   trial->AppendGroup("first", 1);
234   trial->AppendGroup("second", 1);
235   EXPECT_EQ(trial->group_name(), "second");
236 }
237 
TEST_F(FieldTrialTest,MiddleProbabilities_49)238 TEST_F(FieldTrialTest, MiddleProbabilities_49) {
239   MockEntropyProvider entropy_provider(0.49);
240   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
241       "trial name", 10, "Default", entropy_provider);
242   trial->AppendGroup("NotDefault", 5);
243   EXPECT_EQ(trial->group_name(), "NotDefault");
244 }
245 
TEST_F(FieldTrialTest,MiddleProbabilities_51)246 TEST_F(FieldTrialTest, MiddleProbabilities_51) {
247   MockEntropyProvider entropy_provider(0.51);
248   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
249       "trial name", 10, "Default", entropy_provider);
250   trial->AppendGroup("NotDefault", 5);
251   EXPECT_EQ(trial->group_name(), "Default");
252 }
253 
254 // AppendGroup after finalization should not change the winner.
TEST_F(FieldTrialTest,OneWinner)255 TEST_F(FieldTrialTest, OneWinner) {
256   MockEntropyProvider entropy_provider(0.51);
257   scoped_refptr<FieldTrial> trial = FieldTrialList::FactoryGetFieldTrial(
258       "trial name", 10, "Default", entropy_provider);
259 
260   for (int i = 0; i < 5; ++i) {
261     trial->AppendGroup(StringPrintf("%d", i), 1);
262   }
263 
264   // Entropy 0.51 should assign to the 6th group.
265   // It should be declared the winner and stay that way.
266   trial->AppendGroup("Winner", 1);
267   EXPECT_EQ("Winner", trial->group_name());
268 
269   // Note: appending groups after calling group_name() is probably not really
270   // valid usage, since it will DCHECK if the default group won.
271   for (int i = 7; i < 10; ++i) {
272     trial->AppendGroup(StringPrintf("%d", i), 1);
273     EXPECT_EQ("Winner", trial->group_name());
274   }
275 }
276 
TEST_F(FieldTrialTest,ActiveGroups)277 TEST_F(FieldTrialTest, ActiveGroups) {
278   std::string no_group("No Group");
279   scoped_refptr<FieldTrial> trial = CreateFieldTrial(no_group, 10, "Default");
280 
281   // There is no winner yet, so no NameGroupId should be returned.
282   FieldTrial::ActiveGroup active_group;
283   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
284 
285   // Create a single winning group.
286   std::string one_winner("One Winner");
287   trial = CreateFieldTrial(one_winner, 10, "Default");
288   std::string winner("Winner");
289   trial->AppendGroup(winner, 10);
290   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
291   trial->Activate();
292   EXPECT_TRUE(trial->GetActiveGroup(&active_group));
293   EXPECT_EQ(one_winner, active_group.trial_name);
294   EXPECT_EQ(winner, active_group.group_name);
295 
296   std::string multi_group("MultiGroup");
297   scoped_refptr<FieldTrial> multi_group_trial =
298       CreateFieldTrial(multi_group, 9, "Default");
299 
300   multi_group_trial->AppendGroup("Me", 3);
301   multi_group_trial->AppendGroup("You", 3);
302   multi_group_trial->AppendGroup("Them", 3);
303   EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group));
304   multi_group_trial->Activate();
305   EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
306   EXPECT_EQ(multi_group, active_group.trial_name);
307   EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
308 
309   // Now check if the list is built properly...
310   FieldTrial::ActiveGroups active_groups;
311   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
312   EXPECT_EQ(2U, active_groups.size());
313   for (size_t i = 0; i < active_groups.size(); ++i) {
314     // Order is not guaranteed, so check all values.
315     EXPECT_NE(no_group, active_groups[i].trial_name);
316     EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
317                 winner == active_groups[i].group_name);
318     EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
319                 multi_group_trial->group_name() == active_groups[i].group_name);
320   }
321 }
322 
TEST_F(FieldTrialTest,ActiveGroupsNotFinalized)323 TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
324   const char kTrialName[] = "TestTrial";
325   const char kSecondaryGroupName[] = "SecondaryGroup";
326 
327   scoped_refptr<FieldTrial> trial =
328       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
329   trial->AppendGroup(kSecondaryGroupName, 50);
330 
331   // Before |Activate()| is called, |GetActiveGroup()| should return false.
332   FieldTrial::ActiveGroup active_group;
333   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
334 
335   // |GetActiveFieldTrialGroups()| should also not include the trial.
336   FieldTrial::ActiveGroups active_groups;
337   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
338   EXPECT_TRUE(active_groups.empty());
339 
340   // After |Activate()| has been called, both APIs should succeed.
341   trial->Activate();
342 
343   EXPECT_TRUE(trial->GetActiveGroup(&active_group));
344   EXPECT_EQ(kTrialName, active_group.trial_name);
345   EXPECT_TRUE(kDefaultGroupName == active_group.group_name ||
346               kSecondaryGroupName == active_group.group_name);
347 
348   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
349   ASSERT_EQ(1U, active_groups.size());
350   EXPECT_EQ(kTrialName, active_groups[0].trial_name);
351   EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
352 }
353 
TEST_F(FieldTrialTest,GetGroupNameWithoutActivation)354 TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) {
355   const char kTrialName[] = "TestTrial";
356   const char kSecondaryGroupName[] = "SecondaryGroup";
357 
358   scoped_refptr<FieldTrial> trial =
359       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
360   trial->AppendGroup(kSecondaryGroupName, 50);
361 
362   // The trial should start inactive.
363   EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
364 
365   // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
366   std::string group_name = trial->GetGroupNameWithoutActivation();
367   EXPECT_FALSE(group_name.empty());
368   EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
369 
370   // Calling |group_name()| should activate it and return the same group name.
371   EXPECT_EQ(group_name, trial->group_name());
372   EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
373 }
374 
TEST_F(FieldTrialTest,SaveAll)375 TEST_F(FieldTrialTest, SaveAll) {
376   std::string save_string;
377 
378   scoped_refptr<FieldTrial> trial =
379       CreateFieldTrial("Some name", 10, "Default some name");
380   EXPECT_EQ("", trial->group_name_internal());
381   FieldTrialList::AllStatesToString(&save_string);
382   EXPECT_EQ("Some name/Default some name", save_string);
383   // Getting all states should have finalized the trial.
384   EXPECT_EQ("Default some name", trial->group_name_internal());
385   save_string.clear();
386 
387   // Create a winning group.
388   trial = CreateFieldTrial("trial2", 10, "Default some name");
389   trial->AppendGroup("Winner", 10);
390   trial->Activate();
391   FieldTrialList::AllStatesToString(&save_string);
392   EXPECT_EQ("Some name/Default some name/*trial2/Winner", save_string);
393   save_string.clear();
394 
395   // Create a second trial and winning group.
396   scoped_refptr<FieldTrial> trial2 = CreateFieldTrial("xxx", 10, "Default xxx");
397   trial2->AppendGroup("yyyy", 10);
398   trial2->Activate();
399 
400   FieldTrialList::AllStatesToString(&save_string);
401   // We assume names are alphabetized... though this is not critical.
402   EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy",
403             save_string);
404   save_string.clear();
405 
406   // Create a third trial with only the default group.
407   scoped_refptr<FieldTrial> trial3 = CreateFieldTrial("zzz", 10, "default");
408 
409   FieldTrialList::AllStatesToString(&save_string);
410   EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default",
411             save_string);
412 
413   save_string.clear();
414   FieldTrialList::AllStatesToString(&save_string);
415   EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default",
416             save_string);
417 }
418 
TEST_F(FieldTrialTest,Restore)419 TEST_F(FieldTrialTest, Restore) {
420   ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
421   ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
422 
423   FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/");
424 
425   FieldTrial* trial = FieldTrialList::Find("Some_name");
426   ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
427   EXPECT_EQ("Winner", trial->group_name());
428   EXPECT_EQ("Some_name", trial->trial_name());
429   EXPECT_FALSE(trial->IsOverridden());
430 
431   trial = FieldTrialList::Find("xxx");
432   ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
433   EXPECT_EQ("yyyy", trial->group_name());
434   EXPECT_EQ("xxx", trial->trial_name());
435   EXPECT_FALSE(trial->IsOverridden());
436 }
437 
TEST_F(FieldTrialTest,RestoreNotEndingWithSlash)438 TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
439   EXPECT_TRUE(FieldTrialList::CreateTrialsFromString("tname/gname"));
440 
441   FieldTrial* trial = FieldTrialList::Find("tname");
442   ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
443   EXPECT_EQ("gname", trial->group_name());
444   EXPECT_EQ("tname", trial->trial_name());
445 }
446 
TEST_F(FieldTrialTest,BogusRestore)447 TEST_F(FieldTrialTest, BogusRestore) {
448   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingSlash"));
449   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/"));
450   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("noname, only group/"));
451   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("/emptyname"));
452   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("*/emptyname"));
453 }
454 
TEST_F(FieldTrialTest,DuplicateRestore)455 TEST_F(FieldTrialTest, DuplicateRestore) {
456   scoped_refptr<FieldTrial> trial =
457       CreateFieldTrial("Some name", 10, "Default");
458   trial->AppendGroup("Winner", 10);
459   trial->Activate();
460   std::string save_string;
461   FieldTrialList::AllStatesToString(&save_string);
462   // * prefix since it is activated.
463   EXPECT_EQ("*Some name/Winner", save_string);
464 
465   // It is OK if we redundantly specify a winner.
466   EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(save_string));
467 
468   // But it is an error to try to change to a different winner.
469   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/"));
470 }
471 
TEST_F(FieldTrialTest,CreateTrialsFromStringNotActive)472 TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
473   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
474   ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
475   ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/Xyz/zyx/"));
476 
477   FieldTrial::ActiveGroups active_groups;
478   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
479   ASSERT_TRUE(active_groups.empty());
480 
481   // Check that the values still get returned and querying them activates them.
482   EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
483   EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
484 
485   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
486   ASSERT_EQ(2U, active_groups.size());
487   EXPECT_EQ("Abc", active_groups[0].trial_name);
488   EXPECT_EQ("def", active_groups[0].group_name);
489   EXPECT_EQ("Xyz", active_groups[1].trial_name);
490   EXPECT_EQ("zyx", active_groups[1].group_name);
491 }
492 
TEST_F(FieldTrialTest,CreateTrialsFromStringForceActivation)493 TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) {
494   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
495   ASSERT_FALSE(FieldTrialList::TrialExists("def"));
496   ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
497   ASSERT_TRUE(
498       FieldTrialList::CreateTrialsFromString("*Abc/cba/def/fed/*Xyz/zyx/"));
499 
500   FieldTrial::ActiveGroups active_groups;
501   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
502   ASSERT_EQ(2U, active_groups.size());
503   EXPECT_EQ("Abc", active_groups[0].trial_name);
504   EXPECT_EQ("cba", active_groups[0].group_name);
505   EXPECT_EQ("Xyz", active_groups[1].trial_name);
506   EXPECT_EQ("zyx", active_groups[1].group_name);
507 }
508 
TEST_F(FieldTrialTest,CreateTrialsFromStringNotActiveObserver)509 TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
510   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
511 
512   TestFieldTrialObserver observer;
513   ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/"));
514   RunLoop().RunUntilIdle();
515   // Observer shouldn't be notified.
516   EXPECT_TRUE(observer.trial_name().empty());
517 
518   // Check that the values still get returned and querying them activates them.
519   EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
520 
521   EXPECT_EQ("Abc", observer.trial_name());
522   EXPECT_EQ("def", observer.group_name());
523 }
524 
TEST_F(FieldTrialTest,CreateFieldTrial)525 TEST_F(FieldTrialTest, CreateFieldTrial) {
526   ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
527 
528   FieldTrialList::CreateFieldTrial("Some_name", "Winner");
529 
530   FieldTrial* trial = FieldTrialList::Find("Some_name");
531   ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
532   EXPECT_EQ("Winner", trial->group_name());
533   EXPECT_EQ("Some_name", trial->trial_name());
534 }
535 
TEST_F(FieldTrialTest,CreateFieldTrialIsNotActive)536 TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
537   const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
538   const char kWinnerGroup[] = "Winner";
539   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
540   FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
541 
542   FieldTrial::ActiveGroups active_groups;
543   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
544   EXPECT_TRUE(active_groups.empty());
545 }
546 
TEST_F(FieldTrialTest,DuplicateFieldTrial)547 TEST_F(FieldTrialTest, DuplicateFieldTrial) {
548   scoped_refptr<FieldTrial> trial =
549       CreateFieldTrial("Some_name", 10, "Default");
550   trial->AppendGroup("Winner", 10);
551 
552   // It is OK if we redundantly specify a winner.
553   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
554   EXPECT_TRUE(trial1 != nullptr);
555 
556   // But it is an error to try to change to a different winner.
557   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
558   EXPECT_TRUE(trial2 == nullptr);
559 }
560 
TEST_F(FieldTrialTest,ForcedFieldTrials)561 TEST_F(FieldTrialTest, ForcedFieldTrials) {
562   // Validate we keep the forced choice.
563   FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
564                                                               "Force");
565   EXPECT_STREQ("Force", forced_trial->group_name().c_str());
566 
567   scoped_refptr<FieldTrial> factory_trial =
568       CreateFieldTrial("Use the", 1000, "default");
569   EXPECT_EQ(factory_trial.get(), forced_trial);
570 
571   factory_trial->AppendGroup("Force", 100);
572   EXPECT_EQ("Force", factory_trial->group_name());
573   factory_trial->AppendGroup("Dark Side", 100);
574   EXPECT_EQ("Force", factory_trial->group_name());
575   factory_trial->AppendGroup("Duck Tape", 800);
576   EXPECT_EQ("Force", factory_trial->group_name());
577 }
578 
TEST_F(FieldTrialTest,ForcedFieldTrialsDefaultGroup)579 TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
580   // Forcing the default should use the proper group ID.
581   FieldTrial* forced_trial =
582       FieldTrialList::CreateFieldTrial("Trial Name", "Default");
583   scoped_refptr<FieldTrial> factory_trial =
584       CreateFieldTrial("Trial Name", 1000, "Default");
585   EXPECT_EQ(forced_trial, factory_trial.get());
586 
587   factory_trial->AppendGroup("Not Default", 100);
588   EXPECT_STREQ("Default", factory_trial->group_name().c_str());
589 
590   factory_trial->AppendGroup("Not Default Either", 800);
591   EXPECT_STREQ("Default", factory_trial->group_name().c_str());
592 }
593 
TEST_F(FieldTrialTest,SetForced)594 TEST_F(FieldTrialTest, SetForced) {
595   // Start by setting a trial for which we ensure a winner...
596   scoped_refptr<FieldTrial> forced_trial =
597       CreateFieldTrial("Use the", 1, "default");
598   EXPECT_EQ(forced_trial, forced_trial);
599 
600   forced_trial->AppendGroup("Force", 1);
601   EXPECT_EQ("Force", forced_trial->group_name());
602 
603   // Now force it.
604   forced_trial->SetForced();
605 
606   // Now try to set it up differently as a hard coded registration would.
607   scoped_refptr<FieldTrial> hard_coded_trial =
608       CreateFieldTrial("Use the", 1, "default");
609   EXPECT_EQ(hard_coded_trial, forced_trial);
610 
611   hard_coded_trial->AppendGroup("Force", 0);
612   EXPECT_EQ("Force", hard_coded_trial->group_name());
613 
614   // Same thing if we would have done it to win again.
615   scoped_refptr<FieldTrial> other_hard_coded_trial =
616       CreateFieldTrial("Use the", 1, "default");
617   EXPECT_EQ(other_hard_coded_trial, forced_trial);
618 
619   other_hard_coded_trial->AppendGroup("Force", 1);
620   EXPECT_EQ("Force", other_hard_coded_trial->group_name());
621 }
622 
TEST_F(FieldTrialTest,SetForcedDefaultOnly)623 TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
624   const char kTrialName[] = "SetForcedDefaultOnly";
625   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
626 
627   scoped_refptr<FieldTrial> trial =
628       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
629   trial->SetForced();
630 
631   trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
632   EXPECT_EQ(kDefaultGroupName, trial->group_name());
633 }
634 
TEST_F(FieldTrialTest,SetForcedDefaultWithExtraGroup)635 TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
636   const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
637   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
638 
639   scoped_refptr<FieldTrial> trial =
640       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
641   trial->SetForced();
642 
643   trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
644   trial->AppendGroup("Extra", 100);
645   EXPECT_EQ(kDefaultGroupName, trial->group_name());
646 }
647 
TEST_F(FieldTrialTest,SetForcedTurnFeatureOn)648 TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
649   const char kTrialName[] = "SetForcedTurnFeatureOn";
650   const char kExtraGroupName[] = "Extra";
651   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
652 
653   // Simulate a server-side (forced) config that turns the feature on when the
654   // original hard-coded config had it disabled.
655   scoped_refptr<FieldTrial> forced_trial =
656       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
657   forced_trial->AppendGroup(kExtraGroupName, 100);
658   forced_trial->SetForced();
659 
660   scoped_refptr<FieldTrial> client_trial =
661       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
662   client_trial->AppendGroup(kExtraGroupName, 0);
663 
664   EXPECT_FALSE(client_trial->group_reported_);
665   EXPECT_EQ(kExtraGroupName, client_trial->group_name());
666   EXPECT_TRUE(client_trial->group_reported_);
667   EXPECT_EQ(kExtraGroupName, client_trial->group_name());
668 }
669 
TEST_F(FieldTrialTest,SetForcedTurnFeatureOff)670 TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
671   const char kTrialName[] = "SetForcedTurnFeatureOff";
672   const char kExtraGroupName[] = "Extra";
673   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
674 
675   // Simulate a server-side (forced) config that turns the feature off when the
676   // original hard-coded config had it enabled.
677   scoped_refptr<FieldTrial> forced_trial =
678       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
679   forced_trial->AppendGroup(kExtraGroupName, 0);
680   forced_trial->SetForced();
681 
682   scoped_refptr<FieldTrial> client_trial =
683       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
684   client_trial->AppendGroup(kExtraGroupName, 100);
685 
686   EXPECT_FALSE(client_trial->group_reported_);
687   EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
688   EXPECT_TRUE(client_trial->group_reported_);
689   EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
690 }
691 
TEST_F(FieldTrialTest,SetForcedChangeDefault_Default)692 TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
693   const char kTrialName[] = "SetForcedDefaultGroupChange";
694   const char kGroupAName[] = "A";
695   const char kGroupBName[] = "B";
696   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
697 
698   // Simulate a server-side (forced) config that switches which group is default
699   // and ensures that the non-forced code receives the correct group numbers.
700   scoped_refptr<FieldTrial> forced_trial =
701       CreateFieldTrial(kTrialName, 100, kGroupAName);
702   forced_trial->AppendGroup(kGroupBName, 100);
703   forced_trial->SetForced();
704 
705   scoped_refptr<FieldTrial> client_trial =
706       CreateFieldTrial(kTrialName, 100, kGroupBName);
707   client_trial->AppendGroup(kGroupAName, 50);
708 
709   EXPECT_FALSE(client_trial->group_reported_);
710   EXPECT_NE(kGroupAName, client_trial->group_name());
711   EXPECT_TRUE(client_trial->group_reported_);
712   EXPECT_EQ(kGroupBName, client_trial->group_name());
713 }
714 
TEST_F(FieldTrialTest,SetForcedChangeDefault_NonDefault)715 TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
716   const char kTrialName[] = "SetForcedDefaultGroupChange";
717   const char kGroupAName[] = "A";
718   const char kGroupBName[] = "B";
719   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
720 
721   // Simulate a server-side (forced) config that switches which group is default
722   // and ensures that the non-forced code receives the correct group numbers.
723   scoped_refptr<FieldTrial> forced_trial =
724       CreateFieldTrial(kTrialName, 100, kGroupAName);
725   forced_trial->AppendGroup(kGroupBName, 0);
726   forced_trial->SetForced();
727 
728   scoped_refptr<FieldTrial> client_trial =
729       CreateFieldTrial(kTrialName, 100, kGroupBName);
730   client_trial->AppendGroup(kGroupAName, 50);
731 
732   EXPECT_FALSE(client_trial->group_reported_);
733   EXPECT_EQ(kGroupAName, client_trial->group_name());
734   EXPECT_TRUE(client_trial->group_reported_);
735   EXPECT_EQ(kGroupAName, client_trial->group_name());
736 }
737 
TEST_F(FieldTrialTest,Observe)738 TEST_F(FieldTrialTest, Observe) {
739   const char kTrialName[] = "TrialToObserve1";
740   const char kSecondaryGroupName[] = "SecondaryGroup";
741 
742   TestFieldTrialObserver observer;
743   scoped_refptr<FieldTrial> trial =
744       CreateFieldTrial(kTrialName, 100, kDefaultGroupName);
745   trial->AppendGroup(kSecondaryGroupName, 50);
746   const std::string chosen_group_name = trial->group_name();
747   EXPECT_TRUE(chosen_group_name == kDefaultGroupName ||
748               chosen_group_name == kSecondaryGroupName);
749 
750   // The observer should be notified synchronously by the group_name() call.
751   EXPECT_EQ(kTrialName, observer.trial_name());
752   EXPECT_EQ(chosen_group_name, observer.group_name());
753 }
754 
755 // Verify that no hang occurs when a FieldTrial group is selected from a
756 // FieldTrialList::Observer::OnFieldTrialGroupFinalized() notification. If the
757 // FieldTrialList's lock is held when observers are notified, this test will
758 // hang due to reentrant lock acquisition when selecting the FieldTrial group.
TEST_F(FieldTrialTest,ObserveReentrancy)759 TEST_F(FieldTrialTest, ObserveReentrancy) {
760   const char kTrialName1[] = "TrialToObserve1";
761   const char kTrialName2[] = "TrialToObserve2";
762 
763   scoped_refptr<FieldTrial> trial_1 =
764       CreateFieldTrial(kTrialName1, 100, kDefaultGroupName);
765 
766   FieldTrialObserverAccessingGroup observer(trial_1);
767 
768   scoped_refptr<FieldTrial> trial_2 =
769       CreateFieldTrial(kTrialName2, 100, kDefaultGroupName);
770 
771   // No group should be selected for |trial_1| yet.
772   EXPECT_EQ(FieldTrial::kNotFinalized, trial_1->group_);
773 
774   // Force selection of a group for |trial_2|. This will notify |observer| which
775   // will force the selection of a group for |trial_1|. This should not hang.
776   trial_2->Activate();
777 
778   // The above call should have selected a group for |trial_1|.
779   EXPECT_NE(FieldTrial::kNotFinalized, trial_1->group_);
780 }
781 
TEST_F(FieldTrialTest,NotDisabled)782 TEST_F(FieldTrialTest, NotDisabled) {
783   const char kTrialName[] = "NotDisabled";
784   const char kGroupName[] = "Group2";
785   const int kProbability = 100;
786   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
787 
788   scoped_refptr<FieldTrial> trial =
789       CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName);
790   trial->AppendGroup(kGroupName, kProbability);
791   EXPECT_EQ(kGroupName, trial->group_name());
792 }
793 
TEST_F(FieldTrialTest,FloatBoundariesGiveEqualGroupSizes)794 TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
795   const int kBucketCount = 100;
796 
797   // Try each boundary value |i / 100.0| as the entropy value.
798   for (int i = 0; i < kBucketCount; ++i) {
799     const double entropy = i / static_cast<double>(kBucketCount);
800 
801     scoped_refptr<FieldTrial> trial(
802         new FieldTrial("test", kBucketCount, "default", entropy,
803                        /*is_low_anonymity=*/false, /*is_overridden=*/false));
804     for (int j = 0; j < kBucketCount; ++j)
805       trial->AppendGroup(NumberToString(j), 1);
806 
807     EXPECT_EQ(NumberToString(i), trial->group_name());
808   }
809 }
810 
TEST_F(FieldTrialTest,DoesNotSurpassTotalProbability)811 TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
812   const double kEntropyValue = 1.0 - 1e-9;
813   ASSERT_LT(kEntropyValue, 1.0);
814 
815   scoped_refptr<FieldTrial> trial(
816       new FieldTrial("test", 2, "default", kEntropyValue,
817                      /*is_low_anonymity=*/false, /*is_overridden=*/false));
818   trial->AppendGroup("1", 1);
819   trial->AppendGroup("2", 1);
820 
821   EXPECT_EQ("2", trial->group_name());
822 }
823 
TEST_F(FieldTrialTest,CreateSimulatedFieldTrial)824 TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
825   const char kTrialName[] = "CreateSimulatedFieldTrial";
826   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
827 
828   // Different cases to test, e.g. default vs. non default group being chosen.
829   struct {
830     double entropy_value;
831     const char* expected_group;
832   } test_cases[] = {
833     { 0.4, "A" },
834     { 0.85, "B" },
835     { 0.95, kDefaultGroupName },
836   };
837 
838   for (auto& test_case : test_cases) {
839     TestFieldTrialObserver observer;
840     scoped_refptr<FieldTrial> trial(FieldTrial::CreateSimulatedFieldTrial(
841         kTrialName, 100, kDefaultGroupName, test_case.entropy_value));
842     trial->AppendGroup("A", 80);
843     trial->AppendGroup("B", 10);
844     EXPECT_EQ(test_case.expected_group, trial->group_name());
845 
846     // Field trial shouldn't have been registered with the list.
847     EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
848     EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
849 
850     // Observer shouldn't have been notified.
851     RunLoop().RunUntilIdle();
852     EXPECT_TRUE(observer.trial_name().empty());
853 
854     // The trial shouldn't be in the active set of trials.
855     FieldTrial::ActiveGroups active_groups;
856     FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
857     EXPECT_TRUE(active_groups.empty());
858 
859     // The trial shouldn't be listed in the |AllStatesToString()| result.
860     std::string states;
861     FieldTrialList::AllStatesToString(&states);
862     EXPECT_TRUE(states.empty());
863   }
864 }
865 
TEST(FieldTrialTestWithoutList,StatesStringFormat)866 TEST(FieldTrialTestWithoutList, StatesStringFormat) {
867   std::string save_string;
868 
869   test::ScopedFeatureList scoped_feature_list;
870   // The test suite instantiates a FieldTrialList but for the purpose of these
871   // tests it's cleaner to start from scratch.
872   scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
873 
874   // Scoping the first FieldTrialList, as we need another one to test the
875   // importing function.
876   {
877     test::ScopedFeatureList scoped_feature_list1;
878     scoped_feature_list1.InitWithNullFeatureAndFieldTrialLists();
879     FieldTrialList field_trial_list;
880 
881     scoped_refptr<FieldTrial> trial =
882         CreateFieldTrial("Abc", 10, "Default some name");
883     trial->AppendGroup("cba", 10);
884     trial->Activate();
885     scoped_refptr<FieldTrial> trial2 =
886         CreateFieldTrial("Xyz", 10, "Default xxx");
887     trial2->AppendGroup("zyx", 10);
888     trial2->Activate();
889     scoped_refptr<FieldTrial> trial3 = CreateFieldTrial("zzz", 10, "default");
890 
891     FieldTrialList::AllStatesToString(&save_string);
892   }
893 
894   // Starting with a new blank FieldTrialList.
895   test::ScopedFeatureList scoped_feature_list2;
896   scoped_feature_list2.InitWithNullFeatureAndFieldTrialLists();
897   FieldTrialList field_trial_list;
898   ASSERT_TRUE(field_trial_list.CreateTrialsFromString(save_string));
899 
900   FieldTrial::ActiveGroups active_groups;
901   field_trial_list.GetActiveFieldTrialGroups(&active_groups);
902   ASSERT_EQ(2U, active_groups.size());
903   EXPECT_EQ("Abc", active_groups[0].trial_name);
904   EXPECT_EQ("cba", active_groups[0].group_name);
905   EXPECT_EQ("Xyz", active_groups[1].trial_name);
906   EXPECT_EQ("zyx", active_groups[1].group_name);
907   EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
908 }
909 
910 class FieldTrialListTest : public ::testing::Test {
911  public:
FieldTrialListTest()912   FieldTrialListTest() {
913     // The test suite instantiates a FieldTrialList but for the purpose of these
914     // tests it's cleaner to start from scratch.
915     scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
916   }
917 
918  private:
919   test::ScopedFeatureList scoped_feature_list_;
920 };
921 
TEST_F(FieldTrialListTest,InstantiateAllocator)922 TEST_F(FieldTrialListTest, InstantiateAllocator) {
923   test::ScopedFeatureList scoped_feature_list;
924   scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
925 
926   FieldTrialList* field_trial_list = FieldTrialList::GetInstance();
927 
928   FieldTrialList::CreateFieldTrial("Trial1", "Group1");
929 
930   FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
931   const void* memory = field_trial_list->field_trial_allocator_->data();
932   size_t used = field_trial_list->field_trial_allocator_->used();
933 
934   // Ensure that the function is idempotent.
935   FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
936   const void* new_memory = field_trial_list->field_trial_allocator_->data();
937   size_t new_used = field_trial_list->field_trial_allocator_->used();
938   EXPECT_EQ(memory, new_memory);
939   EXPECT_EQ(used, new_used);
940 }
941 
TEST_F(FieldTrialListTest,AddTrialsToAllocator)942 TEST_F(FieldTrialListTest, AddTrialsToAllocator) {
943   std::string save_string;
944   base::ReadOnlySharedMemoryRegion shm_region;
945 
946   // Scoping the first FieldTrialList, as we need another one to test that it
947   // matches.
948   {
949     test::ScopedFeatureList scoped_feature_list1;
950     scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
951 
952     FieldTrialList::CreateFieldTrial("Trial1", "Group1");
953     FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
954     FieldTrialList::AllStatesToString(&save_string);
955     shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
956     ASSERT_TRUE(shm_region.IsValid());
957   }
958 
959   test::ScopedFeatureList scoped_feature_list2;
960   scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
961 
962   // 4 KiB is enough to hold the trials only created for this test.
963   base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
964   ASSERT_TRUE(shm_mapping.IsValid());
965   FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
966   std::string check_string;
967   FieldTrialList::AllStatesToString(&check_string);
968   EXPECT_EQ(save_string, check_string);
969 }
970 
TEST_F(FieldTrialListTest,DoNotAddSimulatedFieldTrialsToAllocator)971 TEST_F(FieldTrialListTest, DoNotAddSimulatedFieldTrialsToAllocator) {
972   constexpr char kTrialName[] = "trial";
973   base::ReadOnlySharedMemoryRegion shm_region;
974   {
975     test::ScopedFeatureList scoped_feature_list1;
976     scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
977 
978     // Create a simulated trial and a real trial and call Activate() on them,
979     // which should only add the real trial to the field trial allocator.
980     FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
981 
982     // This shouldn't add to the allocator.
983     scoped_refptr<FieldTrial> simulated_trial =
984         FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, "Simulated",
985                                               0.95);
986     simulated_trial->Activate();
987 
988     // This should add to the allocator.
989     FieldTrial* real_trial =
990         FieldTrialList::CreateFieldTrial(kTrialName, "Real");
991     real_trial->Activate();
992 
993     shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
994     ASSERT_TRUE(shm_region.IsValid());
995   }
996 
997   // Check that there's only one entry in the allocator.
998   test::ScopedFeatureList scoped_feature_list2;
999   scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
1000   // 4 KiB is enough to hold the trials only created for this test.
1001   base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
1002   ASSERT_TRUE(shm_mapping.IsValid());
1003   FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
1004   std::string check_string;
1005   FieldTrialList::AllStatesToString(&check_string);
1006   ASSERT_EQ(check_string.find("Simulated"), std::string::npos);
1007 }
1008 
TEST_F(FieldTrialListTest,AssociateFieldTrialParams)1009 TEST_F(FieldTrialListTest, AssociateFieldTrialParams) {
1010   test::ScopedFeatureList scoped_feature_list;
1011   scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
1012 
1013   std::string trial_name("Trial1");
1014   std::string group_name("Group1");
1015 
1016   // Create a field trial with some params.
1017   FieldTrialList::CreateFieldTrial(trial_name, group_name);
1018   std::map<std::string, std::string> params;
1019   params["key1"] = "value1";
1020   params["key2"] = "value2";
1021   FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1022       trial_name, group_name, params);
1023   FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1024 
1025   // Clear all cached params from the associator.
1026   FieldTrialParamAssociator::GetInstance()->ClearAllCachedParamsForTesting();
1027   // Check that the params have been cleared from the cache.
1028   std::map<std::string, std::string> cached_params;
1029   FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
1030       trial_name, group_name, &cached_params);
1031   EXPECT_EQ(0U, cached_params.size());
1032 
1033   // Check that we fetch the param from shared memory properly.
1034   std::map<std::string, std::string> new_params;
1035   GetFieldTrialParams(trial_name, &new_params);
1036   EXPECT_EQ("value1", new_params["key1"]);
1037   EXPECT_EQ("value2", new_params["key2"]);
1038   EXPECT_EQ(2U, new_params.size());
1039 }
1040 
TEST_F(FieldTrialListTest,ClearParamsFromSharedMemory)1041 TEST_F(FieldTrialListTest, ClearParamsFromSharedMemory) {
1042   std::string trial_name("Trial1");
1043   std::string group_name("Group1");
1044 
1045   base::ReadOnlySharedMemoryRegion shm_region;
1046   {
1047     test::ScopedFeatureList scoped_feature_list1;
1048     scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
1049 
1050     // Create a field trial with some params.
1051     FieldTrial* trial =
1052         FieldTrialList::CreateFieldTrial(trial_name, group_name);
1053     std::map<std::string, std::string> params;
1054     params["key1"] = "value1";
1055     params["key2"] = "value2";
1056     FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1057         trial_name, group_name, params);
1058     FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1059 
1060     // Clear all params from the associator AND shared memory. The allocated
1061     // segments should be different.
1062     FieldTrial::FieldTrialRef old_ref = trial->ref_;
1063     FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
1064     FieldTrial::FieldTrialRef new_ref = trial->ref_;
1065     EXPECT_NE(old_ref, new_ref);
1066 
1067     // Check that there are no params associated with the field trial anymore.
1068     std::map<std::string, std::string> new_params;
1069     GetFieldTrialParams(trial_name, &new_params);
1070     EXPECT_EQ(0U, new_params.size());
1071 
1072     // Now duplicate the handle so we can easily check that the trial is still
1073     // in shared memory via AllStatesToString.
1074     shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
1075     ASSERT_TRUE(shm_region.IsValid());
1076   }
1077 
1078   // Check that we have the trial.
1079   test::ScopedFeatureList scoped_feature_list2;
1080   scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
1081   // 4 KiB is enough to hold the trials only created for this test.
1082   base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
1083   ASSERT_TRUE(shm_mapping.IsValid());
1084   FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
1085   std::string check_string;
1086   FieldTrialList::AllStatesToString(&check_string);
1087   EXPECT_EQ("*Trial1/Group1", check_string);
1088 }
1089 
TEST_F(FieldTrialListTest,DumpAndFetchFromSharedMemory)1090 TEST_F(FieldTrialListTest, DumpAndFetchFromSharedMemory) {
1091   std::string trial_name("Trial1");
1092   std::string group_name("Group1");
1093 
1094   // Create a field trial with some params.
1095   test::ScopedFeatureList scoped_feature_list;
1096   scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
1097 
1098   FieldTrialList::CreateFieldTrial(trial_name, group_name);
1099   FieldTrialList::CreateFieldTrial("Trial2", "Group2", false,
1100                                    /*is_overridden=*/true);
1101   std::map<std::string, std::string> params;
1102   params["key1"] = "value1";
1103   params["key2"] = "value2";
1104   FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1105       trial_name, group_name, params);
1106 
1107   // 4 KiB is enough to hold the trials only created for this test.
1108   base::MappedReadOnlyRegion shm =
1109       base::ReadOnlySharedMemoryRegion::Create(4 << 10);
1110   ASSERT_TRUE(shm.IsValid());
1111   // We _could_ use PersistentMemoryAllocator, this just has less params.
1112   WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
1113                                                     "");
1114 
1115   // Dump and subsequently retrieve the field trial to |allocator|.
1116   FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(&allocator);
1117   std::vector<const FieldTrial::FieldTrialEntry*> entries =
1118       FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(allocator);
1119 
1120   // Check that we have the entry we put in.
1121   EXPECT_EQ(2u, entries.size());
1122   const FieldTrial::FieldTrialEntry* entry1 = entries[0];
1123   const FieldTrial::FieldTrialEntry* entry2 = entries[1];
1124 
1125   // Check that the trial information matches.
1126   std::string_view shm_trial_name;
1127   std::string_view shm_group_name;
1128   bool overridden;
1129   ASSERT_TRUE(entry1->GetState(shm_trial_name, shm_group_name, overridden));
1130   EXPECT_EQ(trial_name, shm_trial_name);
1131   EXPECT_EQ(group_name, shm_group_name);
1132   EXPECT_FALSE(overridden);
1133 
1134   // Check that the params match.
1135   std::map<std::string, std::string> shm_params;
1136   entry1->GetParams(&shm_params);
1137   EXPECT_EQ(2u, shm_params.size());
1138   EXPECT_EQ("value1", shm_params["key1"]);
1139   EXPECT_EQ("value2", shm_params["key2"]);
1140 
1141   ASSERT_TRUE(entry2->GetState(shm_trial_name, shm_group_name, overridden));
1142   EXPECT_EQ("Trial2", shm_trial_name);
1143   EXPECT_EQ("Group2", shm_group_name);
1144   EXPECT_TRUE(overridden);
1145 }
1146 
1147 #if BUILDFLAG(USE_BLINK)
1148 
1149 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
1150 constexpr GlobalDescriptors::Key kFDKey = 42;
1151 #endif
1152 
1153 BASE_FEATURE(kTestFeatureA, "TestFeatureA", base::FEATURE_DISABLED_BY_DEFAULT);
1154 BASE_FEATURE(kTestFeatureB, "TestFeatureB", base::FEATURE_ENABLED_BY_DEFAULT);
1155 BASE_FEATURE(kTestFeatureC, "TestFeatureC", base::FEATURE_ENABLED_BY_DEFAULT);
1156 
MULTIPROCESS_TEST_MAIN(CreateTrialsInChildProcess)1157 MULTIPROCESS_TEST_MAIN(CreateTrialsInChildProcess) {
1158 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)
1159   // Since the fd value will be mapped from the global descriptors singleton,
1160   // set it there. We use the same value both for the key and the actual fd for
1161   // simplicity.
1162   // Note: On Android, the launch service already sets up the mapping.
1163   base::GlobalDescriptors::GetInstance()->Set(kFDKey, kFDKey);
1164 #endif
1165 
1166   // Create and populate the field trial list singleton.
1167   FieldTrialList field_trial_list;
1168   FieldTrialList::CreateTrialsInChildProcess(*CommandLine::ForCurrentProcess());
1169 
1170   // Create and populate the feature list singleton.
1171   auto feature_list = std::make_unique<FeatureList>();
1172   base::FieldTrialList::ApplyFeatureOverridesInChildProcess(feature_list.get());
1173   FeatureList::SetInstance(std::move(feature_list));
1174 
1175   // Validate the expected field trial and feaure state
1176   CHECK_EQ("Group1", FieldTrialList::FindFullName("Trial1"));
1177   CHECK(FeatureList::IsEnabled(kTestFeatureA));
1178   CHECK(!FeatureList::IsEnabled(kTestFeatureB));
1179   CHECK(!FeatureList::IsEnabled(kTestFeatureC));
1180   return 0;
1181 }
1182 
1183 #if !BUILDFLAG(IS_IOS)
TEST_F(FieldTrialListTest,PassFieldTrialSharedMemoryOnCommandLine)1184 TEST_F(FieldTrialListTest, PassFieldTrialSharedMemoryOnCommandLine) {
1185   // Setup some field trial state.
1186   test::ScopedFeatureList scoped_feature_list1;
1187   scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
1188   std::unique_ptr<FeatureList> feature_list(new FeatureList);
1189   feature_list->InitFromCommandLine(kTestFeatureA.name, kTestFeatureB.name);
1190   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial1", "Group1");
1191   feature_list->RegisterFieldTrialOverride(
1192       kTestFeatureC.name, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
1193   test::ScopedFeatureList scoped_feature_list2;
1194   scoped_feature_list2.InitWithFeatureList(std::move(feature_list));
1195 
1196   // Prepare to launch a child process.
1197   CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
1198   LaunchOptions launch_options;
1199 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
1200   ScopedFD fd_to_share;
1201 #endif
1202   FieldTrialList::PopulateLaunchOptionsWithFieldTrialState(
1203 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
1204       kFDKey, fd_to_share,
1205 #endif
1206       &command_line, &launch_options);
1207 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
1208   launch_options.fds_to_remap.emplace_back(fd_to_share.get(), kFDKey);
1209 #endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
1210 
1211   // The shared memory handle should be specified.
1212   EXPECT_TRUE(command_line.HasSwitch(switches::kFieldTrialHandle));
1213 
1214   // Explicitly specified enabled/disabled features should be specified.
1215   EXPECT_EQ(kTestFeatureA.name,
1216             command_line.GetSwitchValueASCII(switches::kEnableFeatures));
1217   EXPECT_EQ(kTestFeatureB.name,
1218             command_line.GetSwitchValueASCII(switches::kDisableFeatures));
1219 
1220   // Run the child.
1221   Process process = SpawnMultiProcessTestChild("CreateTrialsInChildProcess",
1222                                                command_line, launch_options);
1223   int exit_code = -1;
1224   EXPECT_TRUE(WaitForMultiprocessTestChildExit(
1225       process, TestTimeouts::action_timeout(), &exit_code));
1226   EXPECT_EQ(0, exit_code);
1227 }
1228 #endif
1229 
1230 // Verify that the field trial shared memory handle is really read-only, and
1231 // does not allow writable mappings.
TEST_F(FieldTrialListTest,CheckReadOnlySharedMemoryRegion)1232 TEST_F(FieldTrialListTest, CheckReadOnlySharedMemoryRegion) {
1233   test::ScopedFeatureList scoped_feature_list;
1234   scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
1235 
1236   FieldTrialList::CreateFieldTrial("Trial1", "Group1");
1237 
1238   FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1239 
1240   base::ReadOnlySharedMemoryRegion region =
1241       FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
1242   ASSERT_TRUE(region.IsValid());
1243 
1244   ASSERT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting(
1245       base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
1246           std::move(region))));
1247 }
1248 #endif  // BUILDFLAG(USE_BLINK)
1249 
TEST_F(FieldTrialListTest,TestGetRandomizedFieldTrialCount)1250 TEST_F(FieldTrialListTest, TestGetRandomizedFieldTrialCount) {
1251   EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
1252   EXPECT_EQ(0u, FieldTrialList::GetRandomizedFieldTrialCount());
1253 
1254   const char name1[] = "name 1 test";
1255   const char name2[] = "name 2 test";
1256   const char name3[] = "name 3 test";
1257   const char group1[] = "group 1";
1258 
1259   // Create a field trial with a single group.
1260   scoped_refptr<FieldTrial> trial1 =
1261       FieldTrialList::CreateFieldTrial(name1, group1);
1262   EXPECT_NE(FieldTrial::kNotFinalized, trial1->group_);
1263   EXPECT_EQ(group1, trial1->group_name_internal());
1264 
1265   EXPECT_EQ(1u, FieldTrialList::GetFieldTrialCount());
1266   EXPECT_EQ(0u, FieldTrialList::GetRandomizedFieldTrialCount());
1267 
1268   // Create a randomized field trial.
1269   scoped_refptr<FieldTrial> trial2 =
1270       CreateFieldTrial(name2, 10, "default name 2 test");
1271   EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
1272   EXPECT_EQ(name2, trial2->trial_name());
1273   EXPECT_EQ("", trial2->group_name_internal());
1274 
1275   EXPECT_EQ(2u, FieldTrialList::GetFieldTrialCount());
1276   EXPECT_EQ(1u, FieldTrialList::GetRandomizedFieldTrialCount());
1277 
1278   // Append a first group to trial 2. This doesn't affect GetFieldTrialCount()
1279   // and GetRandomizedFieldTrialCount().
1280   trial2->AppendGroup("a first group", 7);
1281 
1282   EXPECT_EQ(2u, FieldTrialList::GetFieldTrialCount());
1283   EXPECT_EQ(1u, FieldTrialList::GetRandomizedFieldTrialCount());
1284 
1285   // Create another randomized field trial.
1286   scoped_refptr<FieldTrial> trial3 =
1287       CreateFieldTrial(name3, 10, "default name 3 test");
1288   EXPECT_EQ(FieldTrial::kNotFinalized, trial3->group_);
1289   EXPECT_EQ(name3, trial3->trial_name());
1290   EXPECT_EQ("", trial3->group_name_internal());
1291 
1292   EXPECT_EQ(3u, FieldTrialList::GetFieldTrialCount());
1293   EXPECT_EQ(2u, FieldTrialList::GetRandomizedFieldTrialCount());
1294 
1295   // Note: FieldTrialList should delete the objects at shutdown.
1296 }
1297 
TEST_F(FieldTrialTest,TestAllParamsToString)1298 TEST_F(FieldTrialTest, TestAllParamsToString) {
1299   std::string exptected_output = "t1.g1:p1/v1/p2/v2";
1300 
1301   // Create study with one group and two params.
1302   std::map<std::string, std::string> params;
1303   params["p1"] = "v1";
1304   params["p2"] = "v2";
1305   FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1306       "t1", "g1", params);
1307   EXPECT_EQ("", FieldTrialList::AllParamsToString(&MockEscapeQueryParamValue));
1308 
1309   scoped_refptr<FieldTrial> trial1 = CreateFieldTrial("t1", 100, "Default");
1310   trial1->AppendGroup("g1", 100);
1311   trial1->Activate();
1312   EXPECT_EQ(exptected_output,
1313             FieldTrialList::AllParamsToString(&MockEscapeQueryParamValue));
1314 
1315   // Create study with two groups and params that don't belog to the assigned
1316   // group. This should be in the output.
1317   FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1318       "t2", "g2", params);
1319   scoped_refptr<FieldTrial> trial2 = CreateFieldTrial("t2", 100, "Default");
1320   trial2->AppendGroup("g1", 100);
1321   trial2->AppendGroup("g2", 0);
1322   trial2->Activate();
1323   EXPECT_EQ(exptected_output,
1324             FieldTrialList::AllParamsToString(&MockEscapeQueryParamValue));
1325 }
1326 
TEST_F(FieldTrialTest,GetActiveFieldTrialGroups_LowAnonymity)1327 TEST_F(FieldTrialTest, GetActiveFieldTrialGroups_LowAnonymity) {
1328   // Create a field trial with a single winning group.
1329   scoped_refptr<FieldTrial> trial_1 = CreateFieldTrial("Normal", 10, "Default");
1330   trial_1->AppendGroup("Winner 1", 10);
1331   trial_1->Activate();
1332 
1333   // Create a second field trial with a single winning group, marked as
1334   // low-anonymity.
1335   scoped_refptr<FieldTrial> trial_2 = CreateFieldTrial(
1336       "Low anonymity", 10, "Default", /*is_low_anonymity=*/true);
1337   trial_2->AppendGroup("Winner 2", 10);
1338   trial_2->Activate();
1339 
1340   // Check that |FieldTrialList::GetActiveFieldTrialGroups()| does not include
1341   // the low-anonymity trial.
1342   FieldTrial::ActiveGroups active_groups_for_metrics;
1343   FieldTrialList::GetActiveFieldTrialGroups(&active_groups_for_metrics);
1344   EXPECT_THAT(
1345       active_groups_for_metrics,
1346       testing::UnorderedPointwise(CompareActiveGroupToFieldTrial(), {trial_1}));
1347 
1348   // Check that
1349   // |FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups()| includes
1350   // both trials.
1351   FieldTrial::ActiveGroups active_groups;
1352   FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroupsForTesting(
1353       &active_groups);
1354   EXPECT_THAT(active_groups,
1355               testing::UnorderedPointwise(CompareActiveGroupToFieldTrial(),
1356                                           {trial_1, trial_2}));
1357 }
1358 
TEST_F(FieldTrialTest,ObserveIncludingLowAnonymity)1359 TEST_F(FieldTrialTest, ObserveIncludingLowAnonymity) {
1360   TestFieldTrialObserver observer;
1361   TestFieldTrialObserverIncludingLowAnonymity low_anonymity_observer;
1362 
1363   // Create a low-anonymity trial with one active group.
1364   const char kTrialName[] = "TrialToObserve1";
1365   scoped_refptr<FieldTrial> trial = CreateFieldTrial(
1366       kTrialName, 100, kDefaultGroupName, /*is_low_anonymity=*/true);
1367   trial->Activate();
1368 
1369   // Only the low_anonymity_observer should be notified.
1370   EXPECT_EQ("", observer.trial_name());
1371   EXPECT_EQ("", observer.group_name());
1372   EXPECT_EQ(kTrialName, low_anonymity_observer.trial_name());
1373   EXPECT_EQ(kDefaultGroupName, low_anonymity_observer.group_name());
1374 }
1375 
TEST_F(FieldTrialTest,ParseFieldTrialsString)1376 TEST_F(FieldTrialTest, ParseFieldTrialsString) {
1377   std::vector<FieldTrial::State> entries;
1378   ASSERT_TRUE(FieldTrial::ParseFieldTrialsString(
1379       "Trial1/Group1", /*override_trials=*/false, entries));
1380 
1381   ASSERT_EQ(entries.size(), 1ul);
1382   const FieldTrial::State& entry = entries[0];
1383   EXPECT_EQ("Trial1", entry.trial_name);
1384   EXPECT_EQ("Group1", entry.group_name);
1385   EXPECT_EQ(false, entry.activated);
1386   EXPECT_EQ(false, entry.is_overridden);
1387 }
1388 
TEST_F(FieldTrialTest,ParseFieldTrialsStringTwoStudies)1389 TEST_F(FieldTrialTest, ParseFieldTrialsStringTwoStudies) {
1390   std::vector<FieldTrial::State> entries;
1391   ASSERT_TRUE(FieldTrial::ParseFieldTrialsString(
1392       "Trial1/Group1/*Trial2/Group2/", /*override_trials=*/false, entries));
1393 
1394   ASSERT_EQ(entries.size(), 2ul);
1395   const FieldTrial::State& entry1 = entries[0];
1396   EXPECT_EQ("Trial1", entry1.trial_name);
1397   EXPECT_EQ("Group1", entry1.group_name);
1398   EXPECT_EQ(false, entry1.activated);
1399   EXPECT_EQ(false, entry1.is_overridden);
1400 
1401   const FieldTrial::State& entry2 = entries[1];
1402   EXPECT_EQ("Trial2", entry2.trial_name);
1403   EXPECT_EQ("Group2", entry2.group_name);
1404   EXPECT_EQ(true, entry2.activated);
1405   EXPECT_EQ(false, entry2.is_overridden);
1406 }
1407 
TEST_F(FieldTrialTest,ParseFieldTrialsStringEmpty)1408 TEST_F(FieldTrialTest, ParseFieldTrialsStringEmpty) {
1409   std::vector<FieldTrial::State> entries;
1410   ASSERT_TRUE(FieldTrial::ParseFieldTrialsString("", /*override_trials=*/false,
1411                                                  entries));
1412 
1413   ASSERT_EQ(entries.size(), 0ul);
1414 }
1415 
TEST_F(FieldTrialTest,ParseFieldTrialsStringInvalid)1416 TEST_F(FieldTrialTest, ParseFieldTrialsStringInvalid) {
1417   std::vector<FieldTrial::State> entries;
1418   EXPECT_FALSE(FieldTrial::ParseFieldTrialsString(
1419       "A/", /*override_trials=*/false, entries));
1420   EXPECT_FALSE(FieldTrial::ParseFieldTrialsString(
1421       "/A", /*override_trials=*/false, entries));
1422   EXPECT_FALSE(FieldTrial::ParseFieldTrialsString(
1423       "//", /*override_trials=*/false, entries));
1424   EXPECT_FALSE(FieldTrial::ParseFieldTrialsString(
1425       "///", /*override_trials=*/false, entries));
1426 }
1427 
TEST_F(FieldTrialTest,BuildFieldTrialStateString)1428 TEST_F(FieldTrialTest, BuildFieldTrialStateString) {
1429   FieldTrial::State state1;
1430   state1.trial_name = "Trial";
1431   state1.group_name = "Group";
1432   state1.activated = false;
1433 
1434   FieldTrial::State state2;
1435   state2.trial_name = "Foo";
1436   state2.group_name = "Bar";
1437   state2.activated = true;
1438 
1439   EXPECT_EQ("Trial/Group", FieldTrial::BuildFieldTrialStateString({state1}));
1440   EXPECT_EQ("Trial/Group/*Foo/Bar",
1441             FieldTrial::BuildFieldTrialStateString({state1, state2}));
1442 }
1443 
1444 }  // namespace base
1445