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