• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/metrics/field_trial.h"
6 
7 #include "base/message_loop/message_loop.h"
8 #include "base/rand_util.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace base {
15 
16 namespace {
17 
18 // Default group name used by several tests.
19 const char kDefaultGroupName[] = "DefaultGroup";
20 
21 // Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
CreateFieldTrial(const std::string & trial_name,int total_probability,const std::string & default_group_name,int * default_group_number)22 scoped_refptr<base::FieldTrial> CreateFieldTrial(
23     const std::string& trial_name,
24     int total_probability,
25     const std::string& default_group_name,
26     int* default_group_number) {
27   return FieldTrialList::FactoryGetFieldTrial(
28       trial_name, total_probability, default_group_name,
29       base::FieldTrialList::kNoExpirationYear, 1, 1,
30       base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
31 }
32 
GetLastYear()33 int GetLastYear() {
34   Time last_year_time = Time::NowFromSystemTime() - TimeDelta::FromDays(365);
35   Time::Exploded exploded;
36   last_year_time.LocalExplode(&exploded);
37   return exploded.year;
38 }
39 
40 // FieldTrialList::Observer implementation for testing.
41 class TestFieldTrialObserver : public FieldTrialList::Observer {
42  public:
TestFieldTrialObserver()43   TestFieldTrialObserver() {
44     FieldTrialList::AddObserver(this);
45   }
46 
~TestFieldTrialObserver()47   virtual ~TestFieldTrialObserver() {
48     FieldTrialList::RemoveObserver(this);
49   }
50 
OnFieldTrialGroupFinalized(const std::string & trial,const std::string & group)51   virtual void OnFieldTrialGroupFinalized(const std::string& trial,
52                                           const std::string& group) OVERRIDE {
53     trial_name_ = trial;
54     group_name_ = group;
55   }
56 
trial_name() const57   const std::string& trial_name() const { return trial_name_; }
group_name() const58   const std::string& group_name() const { return group_name_; }
59 
60  private:
61   std::string trial_name_;
62   std::string group_name_;
63 
64   DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver);
65 };
66 
67 }  // namespace
68 
69 class FieldTrialTest : public testing::Test {
70  public:
FieldTrialTest()71   FieldTrialTest() : trial_list_(NULL) {}
72 
73  private:
74   MessageLoop message_loop_;
75   FieldTrialList trial_list_;
76 };
77 
78 // Test registration, and also check that destructors are called for trials
79 // (and that Valgrind doesn't catch us leaking).
TEST_F(FieldTrialTest,Registration)80 TEST_F(FieldTrialTest, Registration) {
81   const char* name1 = "name 1 test";
82   const char* name2 = "name 2 test";
83   EXPECT_FALSE(FieldTrialList::Find(name1));
84   EXPECT_FALSE(FieldTrialList::Find(name2));
85 
86   scoped_refptr<FieldTrial> trial1 =
87       CreateFieldTrial(name1, 10, "default name 1 test", NULL);
88   EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
89   EXPECT_EQ(name1, trial1->trial_name());
90   EXPECT_EQ("", trial1->group_name_internal());
91 
92   trial1->AppendGroup(std::string(), 7);
93 
94   EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
95   EXPECT_FALSE(FieldTrialList::Find(name2));
96 
97   scoped_refptr<FieldTrial> trial2 =
98       CreateFieldTrial(name2, 10, "default name 2 test", NULL);
99   EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
100   EXPECT_EQ(name2, trial2->trial_name());
101   EXPECT_EQ("", trial2->group_name_internal());
102 
103   trial2->AppendGroup("a first group", 7);
104 
105   EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
106   EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
107   // Note: FieldTrialList should delete the objects at shutdown.
108 }
109 
TEST_F(FieldTrialTest,AbsoluteProbabilities)110 TEST_F(FieldTrialTest, AbsoluteProbabilities) {
111   char always_true[] = " always true";
112   char default_always_true[] = " default always true";
113   char always_false[] = " always false";
114   char default_always_false[] = " default always false";
115   for (int i = 1; i < 250; ++i) {
116     // Try lots of names, by changing the first character of the name.
117     always_true[0] = i;
118     default_always_true[0] = i;
119     always_false[0] = i;
120     default_always_false[0] = i;
121 
122     scoped_refptr<FieldTrial> trial_true =
123         CreateFieldTrial(always_true, 10, default_always_true, NULL);
124     const std::string winner = "TheWinner";
125     int winner_group = trial_true->AppendGroup(winner, 10);
126 
127     EXPECT_EQ(winner_group, trial_true->group());
128     EXPECT_EQ(winner, trial_true->group_name());
129 
130     scoped_refptr<FieldTrial> trial_false =
131         CreateFieldTrial(always_false, 10, default_always_false, NULL);
132     int loser_group = trial_false->AppendGroup("ALoser", 0);
133 
134     EXPECT_NE(loser_group, trial_false->group());
135   }
136 }
137 
TEST_F(FieldTrialTest,RemainingProbability)138 TEST_F(FieldTrialTest, RemainingProbability) {
139   // First create a test that hasn't had a winner yet.
140   const std::string winner = "Winner";
141   const std::string loser = "Loser";
142   scoped_refptr<FieldTrial> trial;
143   int counter = 0;
144   int default_group_number = -1;
145   do {
146     std::string name = StringPrintf("trial%d", ++counter);
147     trial = CreateFieldTrial(name, 10, winner, &default_group_number);
148     trial->AppendGroup(loser, 5);  // 50% chance of not being chosen.
149     // If a group is not assigned, group_ will be kNotFinalized.
150   } while (trial->group_ != FieldTrial::kNotFinalized);
151 
152   // And that 'default' group (winner) should always win.
153   EXPECT_EQ(default_group_number, trial->group());
154 
155   // And that winner should ALWAYS win.
156   EXPECT_EQ(winner, trial->group_name());
157 }
158 
TEST_F(FieldTrialTest,FiftyFiftyProbability)159 TEST_F(FieldTrialTest, FiftyFiftyProbability) {
160   // Check that even with small divisors, we have the proper probabilities, and
161   // all outcomes are possible.  Since this is a 50-50 test, it should get both
162   // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
163   // with probability around 1 in 2^99).
164   bool first_winner = false;
165   bool second_winner = false;
166   int counter = 0;
167   do {
168     std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
169     std::string default_group_name = base::StringPrintf("Default FiftyFifty%d",
170                                                         ++counter);
171     scoped_refptr<FieldTrial> trial =
172         CreateFieldTrial(name, 2, default_group_name, NULL);
173     trial->AppendGroup("first", 1);  // 50% chance of being chosen.
174     // If group_ is kNotFinalized, then a group assignement hasn't been done.
175     if (trial->group_ != FieldTrial::kNotFinalized) {
176       first_winner = true;
177       continue;
178     }
179     trial->AppendGroup("second", 1);  // Always chosen at this point.
180     EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
181     second_winner = true;
182   } while ((!second_winner || !first_winner) && counter < 100);
183   EXPECT_TRUE(second_winner);
184   EXPECT_TRUE(first_winner);
185 }
186 
TEST_F(FieldTrialTest,MiddleProbabilities)187 TEST_F(FieldTrialTest, MiddleProbabilities) {
188   char name[] = " same name";
189   char default_group_name[] = " default same name";
190   bool false_event_seen = false;
191   bool true_event_seen = false;
192   for (int i = 1; i < 250; ++i) {
193     name[0] = i;
194     default_group_name[0] = i;
195     scoped_refptr<FieldTrial> trial =
196         CreateFieldTrial(name, 10, default_group_name, NULL);
197     int might_win = trial->AppendGroup("MightWin", 5);
198 
199     if (trial->group() == might_win) {
200       true_event_seen = true;
201     } else {
202       false_event_seen = true;
203     }
204     if (false_event_seen && true_event_seen)
205       return;  // Successful test!!!
206   }
207   // Very surprising to get here. Probability should be around 1 in 2 ** 250.
208   // One of the following will fail.
209   EXPECT_TRUE(false_event_seen);
210   EXPECT_TRUE(true_event_seen);
211 }
212 
TEST_F(FieldTrialTest,OneWinner)213 TEST_F(FieldTrialTest, OneWinner) {
214   char name[] = "Some name";
215   char default_group_name[] = "Default some name";
216   int group_count(10);
217 
218   int default_group_number = -1;
219   scoped_refptr<FieldTrial> trial =
220       CreateFieldTrial(name, group_count, default_group_name, NULL);
221   int winner_index(-2);
222   std::string winner_name;
223 
224   for (int i = 1; i <= group_count; ++i) {
225     int might_win = trial->AppendGroup(std::string(), 1);
226 
227     // Because we keep appending groups, we want to see if the last group that
228     // was added has been assigned or not.
229     if (trial->group_ == might_win) {
230       EXPECT_EQ(-2, winner_index);
231       winner_index = might_win;
232       StringAppendF(&winner_name, "%d", might_win);
233       EXPECT_EQ(winner_name, trial->group_name());
234     }
235   }
236   EXPECT_GE(winner_index, 0);
237   // Since all groups cover the total probability, we should not have
238   // chosen the default group.
239   EXPECT_NE(trial->group(), default_group_number);
240   EXPECT_EQ(trial->group(), winner_index);
241   EXPECT_EQ(trial->group_name(), winner_name);
242 }
243 
TEST_F(FieldTrialTest,DisableProbability)244 TEST_F(FieldTrialTest, DisableProbability) {
245   const std::string default_group_name = "Default group";
246   const std::string loser = "Loser";
247   const std::string name = "Trial";
248 
249   // Create a field trail that has expired.
250   int default_group_number = -1;
251   FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
252       name, 1000000000, default_group_name, GetLastYear(), 1, 1,
253       FieldTrial::SESSION_RANDOMIZED,
254       &default_group_number);
255   trial->AppendGroup(loser, 999999999);  // 99.9999999% chance of being chosen.
256 
257   // Because trial has expired, we should always be in the default group.
258   EXPECT_EQ(default_group_number, trial->group());
259 
260   // And that default_group_name should ALWAYS win.
261   EXPECT_EQ(default_group_name, trial->group_name());
262 }
263 
TEST_F(FieldTrialTest,ActiveGroups)264 TEST_F(FieldTrialTest, ActiveGroups) {
265   std::string no_group("No Group");
266   scoped_refptr<FieldTrial> trial =
267       CreateFieldTrial(no_group, 10, "Default", NULL);
268 
269   // There is no winner yet, so no NameGroupId should be returned.
270   FieldTrial::ActiveGroup active_group;
271   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
272 
273   // Create a single winning group.
274   std::string one_winner("One Winner");
275   trial = CreateFieldTrial(one_winner, 10, "Default", NULL);
276   std::string winner("Winner");
277   trial->AppendGroup(winner, 10);
278   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
279   // Finalize the group selection by accessing the selected group.
280   trial->group();
281   EXPECT_TRUE(trial->GetActiveGroup(&active_group));
282   EXPECT_EQ(one_winner, active_group.trial_name);
283   EXPECT_EQ(winner, active_group.group_name);
284 
285   std::string multi_group("MultiGroup");
286   scoped_refptr<FieldTrial> multi_group_trial =
287       CreateFieldTrial(multi_group, 9, "Default", NULL);
288 
289   multi_group_trial->AppendGroup("Me", 3);
290   multi_group_trial->AppendGroup("You", 3);
291   multi_group_trial->AppendGroup("Them", 3);
292   EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group));
293   // Finalize the group selection by accessing the selected group.
294   multi_group_trial->group();
295   EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
296   EXPECT_EQ(multi_group, active_group.trial_name);
297   EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
298 
299   // Now check if the list is built properly...
300   FieldTrial::ActiveGroups active_groups;
301   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
302   EXPECT_EQ(2U, active_groups.size());
303   for (size_t i = 0; i < active_groups.size(); ++i) {
304     // Order is not guaranteed, so check all values.
305     EXPECT_NE(no_group, active_groups[i].trial_name);
306     EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
307                 winner == active_groups[i].group_name);
308     EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
309                 multi_group_trial->group_name() == active_groups[i].group_name);
310   }
311 }
312 
TEST_F(FieldTrialTest,ActiveGroupsNotFinalized)313 TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
314   const char kTrialName[] = "TestTrial";
315   const char kSecondaryGroupName[] = "SecondaryGroup";
316 
317   int default_group = -1;
318   scoped_refptr<FieldTrial> trial =
319       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
320   const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
321 
322   // Before |group()| is called, |GetActiveGroup()| should return false.
323   FieldTrial::ActiveGroup active_group;
324   EXPECT_FALSE(trial->GetActiveGroup(&active_group));
325 
326   // |GetActiveFieldTrialGroups()| should also not include the trial.
327   FieldTrial::ActiveGroups active_groups;
328   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
329   EXPECT_TRUE(active_groups.empty());
330 
331   // After |group()| has been called, both APIs should succeed.
332   const int chosen_group = trial->group();
333   EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
334 
335   EXPECT_TRUE(trial->GetActiveGroup(&active_group));
336   EXPECT_EQ(kTrialName, active_group.trial_name);
337   if (chosen_group == default_group)
338     EXPECT_EQ(kDefaultGroupName, active_group.group_name);
339   else
340     EXPECT_EQ(kSecondaryGroupName, active_group.group_name);
341 
342   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
343   ASSERT_EQ(1U, active_groups.size());
344   EXPECT_EQ(kTrialName, active_groups[0].trial_name);
345   EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
346 }
347 
TEST_F(FieldTrialTest,Save)348 TEST_F(FieldTrialTest, Save) {
349   std::string save_string;
350 
351   scoped_refptr<FieldTrial> trial =
352       CreateFieldTrial("Some name", 10, "Default some name", NULL);
353   // There is no winner yet, so no textual group name is associated with trial.
354   // In this case, the trial should not be included.
355   EXPECT_EQ("", trial->group_name_internal());
356   FieldTrialList::StatesToString(&save_string);
357   EXPECT_EQ("", save_string);
358   save_string.clear();
359 
360   // Create a winning group.
361   trial->AppendGroup("Winner", 10);
362   // Finalize the group selection by accessing the selected group.
363   trial->group();
364   FieldTrialList::StatesToString(&save_string);
365   EXPECT_EQ("Some name/Winner/", save_string);
366   save_string.clear();
367 
368   // Create a second trial and winning group.
369   scoped_refptr<FieldTrial> trial2 =
370       CreateFieldTrial("xxx", 10, "Default xxx", NULL);
371   trial2->AppendGroup("yyyy", 10);
372   // Finalize the group selection by accessing the selected group.
373   trial2->group();
374 
375   FieldTrialList::StatesToString(&save_string);
376   // We assume names are alphabetized... though this is not critical.
377   EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string);
378   save_string.clear();
379 
380   // Create a third trial with only the default group.
381   scoped_refptr<FieldTrial> trial3 =
382       CreateFieldTrial("zzz", 10, "default", NULL);
383   // Finalize the group selection by accessing the selected group.
384   trial3->group();
385 
386   FieldTrialList::StatesToString(&save_string);
387   EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
388 }
389 
TEST_F(FieldTrialTest,Restore)390 TEST_F(FieldTrialTest, Restore) {
391   ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
392   ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
393 
394   FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/",
395                                          FieldTrialList::DONT_ACTIVATE_TRIALS,
396                                          std::set<std::string>());
397 
398   FieldTrial* trial = FieldTrialList::Find("Some_name");
399   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
400   EXPECT_EQ("Winner", trial->group_name());
401   EXPECT_EQ("Some_name", trial->trial_name());
402 
403   trial = FieldTrialList::Find("xxx");
404   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
405   EXPECT_EQ("yyyy", trial->group_name());
406   EXPECT_EQ("xxx", trial->trial_name());
407 }
408 
TEST_F(FieldTrialTest,RestoreNotEndingWithSlash)409 TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
410   EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
411       "tname/gname", FieldTrialList::DONT_ACTIVATE_TRIALS,
412       std::set<std::string>()));
413 
414   FieldTrial* trial = FieldTrialList::Find("tname");
415   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
416   EXPECT_EQ("gname", trial->group_name());
417   EXPECT_EQ("tname", trial->trial_name());
418 }
419 
TEST_F(FieldTrialTest,BogusRestore)420 TEST_F(FieldTrialTest, BogusRestore) {
421   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
422       "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS,
423       std::set<std::string>()));
424   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
425       "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS,
426       std::set<std::string>()));
427   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
428       "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS,
429       std::set<std::string>()));
430 }
431 
TEST_F(FieldTrialTest,DuplicateRestore)432 TEST_F(FieldTrialTest, DuplicateRestore) {
433   scoped_refptr<FieldTrial> trial =
434       CreateFieldTrial("Some name", 10, "Default", NULL);
435   trial->AppendGroup("Winner", 10);
436   // Finalize the group selection by accessing the selected group.
437   trial->group();
438   std::string save_string;
439   FieldTrialList::StatesToString(&save_string);
440   EXPECT_EQ("Some name/Winner/", save_string);
441 
442   // It is OK if we redundantly specify a winner.
443   EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
444       save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
445       std::set<std::string>()));
446 
447   // But it is an error to try to change to a different winner.
448   EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
449       "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS,
450       std::set<std::string>()));
451 }
452 
TEST_F(FieldTrialTest,CreateTrialsFromStringActive)453 TEST_F(FieldTrialTest, CreateTrialsFromStringActive) {
454   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
455   ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
456   ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
457       "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS,
458       std::set<std::string>()));
459 
460   FieldTrial::ActiveGroups active_groups;
461   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
462   ASSERT_EQ(2U, active_groups.size());
463   EXPECT_EQ("Abc", active_groups[0].trial_name);
464   EXPECT_EQ("def", active_groups[0].group_name);
465   EXPECT_EQ("Xyz", active_groups[1].trial_name);
466   EXPECT_EQ("zyx", active_groups[1].group_name);
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(
473       "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS,
474       std::set<std::string>()));
475 
476   FieldTrial::ActiveGroups active_groups;
477   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
478   ASSERT_TRUE(active_groups.empty());
479 
480   // Check that the values still get returned and querying them activates them.
481   EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
482   EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
483 
484   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
485   ASSERT_EQ(2U, active_groups.size());
486   EXPECT_EQ("Abc", active_groups[0].trial_name);
487   EXPECT_EQ("def", active_groups[0].group_name);
488   EXPECT_EQ("Xyz", active_groups[1].trial_name);
489   EXPECT_EQ("zyx", active_groups[1].group_name);
490 }
491 
TEST_F(FieldTrialTest,CreateTrialsFromStringActiveObserver)492 TEST_F(FieldTrialTest, CreateTrialsFromStringActiveObserver) {
493   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
494 
495   TestFieldTrialObserver observer;
496   ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
497       "Abc/def/", FieldTrialList::ACTIVATE_TRIALS, std::set<std::string>()));
498 
499   RunLoop().RunUntilIdle();
500   EXPECT_EQ("Abc", observer.trial_name());
501   EXPECT_EQ("def", observer.group_name());
502 }
503 
TEST_F(FieldTrialTest,CreateTrialsFromStringNotActiveObserver)504 TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
505   ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
506 
507   TestFieldTrialObserver observer;
508   ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
509       "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS,
510       std::set<std::string>()));
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   RunLoop().RunUntilIdle();
519   EXPECT_EQ("Abc", observer.trial_name());
520   EXPECT_EQ("def", observer.group_name());
521 }
522 
TEST_F(FieldTrialTest,CreateTrialsFromStringWithIgnoredFieldTrials)523 TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) {
524   ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
525   ASSERT_FALSE(FieldTrialList::TrialExists("Foo"));
526   ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
527   ASSERT_FALSE(FieldTrialList::TrialExists("Bar"));
528   ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
529 
530   std::set<std::string> ignored_trial_names;
531   ignored_trial_names.insert("Unaccepted1");
532   ignored_trial_names.insert("Unaccepted2");
533   ignored_trial_names.insert("Unaccepted3");
534 
535   FieldTrialList::CreateTrialsFromString(
536       "Unaccepted1/Unaccepted1_name/"
537       "Foo/Foo_name/"
538       "Unaccepted2/Unaccepted2_name/"
539       "Bar/Bar_name/"
540       "Unaccepted3/Unaccepted3_name/",
541       FieldTrialList::DONT_ACTIVATE_TRIALS,
542       ignored_trial_names);
543 
544   EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
545   EXPECT_TRUE(FieldTrialList::TrialExists("Foo"));
546   EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
547   EXPECT_TRUE(FieldTrialList::TrialExists("Bar"));
548   EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
549 
550   FieldTrial::ActiveGroups active_groups;
551   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
552   EXPECT_TRUE(active_groups.empty());
553 
554   FieldTrial* trial = FieldTrialList::Find("Foo");
555   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
556   EXPECT_EQ("Foo", trial->trial_name());
557   EXPECT_EQ("Foo_name", trial->group_name());
558 
559   trial = FieldTrialList::Find("Bar");
560   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
561   EXPECT_EQ("Bar", trial->trial_name());
562   EXPECT_EQ("Bar_name", trial->group_name());
563 }
564 
TEST_F(FieldTrialTest,CreateFieldTrial)565 TEST_F(FieldTrialTest, CreateFieldTrial) {
566   ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
567 
568   FieldTrialList::CreateFieldTrial("Some_name", "Winner");
569 
570   FieldTrial* trial = FieldTrialList::Find("Some_name");
571   ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
572   EXPECT_EQ("Winner", trial->group_name());
573   EXPECT_EQ("Some_name", trial->trial_name());
574 }
575 
TEST_F(FieldTrialTest,CreateFieldTrialIsNotActive)576 TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
577   const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
578   const char kWinnerGroup[] = "Winner";
579   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
580   FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
581 
582   FieldTrial::ActiveGroups active_groups;
583   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
584   EXPECT_TRUE(active_groups.empty());
585 }
586 
TEST_F(FieldTrialTest,DuplicateFieldTrial)587 TEST_F(FieldTrialTest, DuplicateFieldTrial) {
588   scoped_refptr<FieldTrial> trial =
589       CreateFieldTrial("Some_name", 10, "Default", NULL);
590   trial->AppendGroup("Winner", 10);
591 
592   // It is OK if we redundantly specify a winner.
593   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
594   EXPECT_TRUE(trial1 != NULL);
595 
596   // But it is an error to try to change to a different winner.
597   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
598   EXPECT_TRUE(trial2 == NULL);
599 }
600 
TEST_F(FieldTrialTest,DisableImmediately)601 TEST_F(FieldTrialTest, DisableImmediately) {
602   int default_group_number = -1;
603   scoped_refptr<FieldTrial> trial =
604       CreateFieldTrial("trial", 100, "default", &default_group_number);
605   trial->Disable();
606   ASSERT_EQ("default", trial->group_name());
607   ASSERT_EQ(default_group_number, trial->group());
608 }
609 
TEST_F(FieldTrialTest,DisableAfterInitialization)610 TEST_F(FieldTrialTest, DisableAfterInitialization) {
611   scoped_refptr<FieldTrial> trial =
612       CreateFieldTrial("trial", 100, "default", NULL);
613   trial->AppendGroup("non_default", 100);
614   trial->Disable();
615   ASSERT_EQ("default", trial->group_name());
616 }
617 
TEST_F(FieldTrialTest,ForcedFieldTrials)618 TEST_F(FieldTrialTest, ForcedFieldTrials) {
619   // Validate we keep the forced choice.
620   FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
621                                                               "Force");
622   EXPECT_STREQ("Force", forced_trial->group_name().c_str());
623 
624   int default_group_number = -1;
625   scoped_refptr<FieldTrial> factory_trial =
626       CreateFieldTrial("Use the", 1000, "default", &default_group_number);
627   EXPECT_EQ(factory_trial.get(), forced_trial);
628 
629   int chosen_group = factory_trial->AppendGroup("Force", 100);
630   EXPECT_EQ(chosen_group, factory_trial->group());
631   int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100);
632   EXPECT_NE(chosen_group, not_chosen_group);
633 
634   // Since we didn't force the default group, we should not be returned the
635   // chosen group as the default group.
636   EXPECT_NE(default_group_number, chosen_group);
637   int new_group = factory_trial->AppendGroup("Duck Tape", 800);
638   EXPECT_NE(chosen_group, new_group);
639   // The new group should not be the default group either.
640   EXPECT_NE(default_group_number, new_group);
641 }
642 
TEST_F(FieldTrialTest,ForcedFieldTrialsDefaultGroup)643 TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
644   // Forcing the default should use the proper group ID.
645   FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name",
646                                                               "Default");
647   int default_group_number = -1;
648   scoped_refptr<FieldTrial> factory_trial =
649       CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number);
650   EXPECT_EQ(forced_trial, factory_trial.get());
651 
652   int other_group = factory_trial->AppendGroup("Not Default", 100);
653   EXPECT_STREQ("Default", factory_trial->group_name().c_str());
654   EXPECT_EQ(default_group_number, factory_trial->group());
655   EXPECT_NE(other_group, factory_trial->group());
656 
657   int new_other_group = factory_trial->AppendGroup("Not Default Either", 800);
658   EXPECT_NE(new_other_group, factory_trial->group());
659 }
660 
TEST_F(FieldTrialTest,SetForced)661 TEST_F(FieldTrialTest, SetForced) {
662   // Start by setting a trial for which we ensure a winner...
663   int default_group_number = -1;
664   scoped_refptr<FieldTrial> forced_trial =
665       CreateFieldTrial("Use the", 1, "default", &default_group_number);
666   EXPECT_EQ(forced_trial, forced_trial);
667 
668   int forced_group = forced_trial->AppendGroup("Force", 1);
669   EXPECT_EQ(forced_group, forced_trial->group());
670 
671   // Now force it.
672   forced_trial->SetForced();
673 
674   // Now try to set it up differently as a hard coded registration would.
675   scoped_refptr<FieldTrial> hard_coded_trial =
676       CreateFieldTrial("Use the", 1, "default", &default_group_number);
677   EXPECT_EQ(hard_coded_trial, forced_trial);
678 
679   int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
680   EXPECT_EQ(forced_group, hard_coded_trial->group());
681   EXPECT_EQ(forced_group, would_lose_group);
682 
683   // Same thing if we would have done it to win again.
684   scoped_refptr<FieldTrial> other_hard_coded_trial =
685       CreateFieldTrial("Use the", 1, "default", &default_group_number);
686   EXPECT_EQ(other_hard_coded_trial, forced_trial);
687 
688   int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
689   EXPECT_EQ(forced_group, other_hard_coded_trial->group());
690   EXPECT_EQ(forced_group, would_win_group);
691 }
692 
TEST_F(FieldTrialTest,SetForcedDefaultOnly)693 TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
694   const char kTrialName[] = "SetForcedDefaultOnly";
695   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
696 
697   int default_group = -1;
698   scoped_refptr<FieldTrial> trial =
699       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
700   trial->SetForced();
701 
702   trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
703   EXPECT_EQ(default_group, trial->group());
704   EXPECT_EQ(kDefaultGroupName, trial->group_name());
705 }
706 
TEST_F(FieldTrialTest,SetForcedDefaultWithExtraGroup)707 TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
708   const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
709   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
710 
711   int default_group = -1;
712   scoped_refptr<FieldTrial> trial =
713       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
714   trial->SetForced();
715 
716   trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
717   const int extra_group = trial->AppendGroup("Extra", 100);
718   EXPECT_EQ(default_group, trial->group());
719   EXPECT_NE(extra_group, trial->group());
720   EXPECT_EQ(kDefaultGroupName, trial->group_name());
721 }
722 
TEST_F(FieldTrialTest,SetForcedTurnFeatureOn)723 TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
724   const char kTrialName[] = "SetForcedTurnFeatureOn";
725   const char kExtraGroupName[] = "Extra";
726   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
727 
728   // Simulate a server-side (forced) config that turns the feature on when the
729   // original hard-coded config had it disabled.
730   scoped_refptr<FieldTrial> forced_trial =
731       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
732   forced_trial->AppendGroup(kExtraGroupName, 100);
733   forced_trial->SetForced();
734 
735   int default_group = -1;
736   scoped_refptr<FieldTrial> client_trial =
737       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
738   const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0);
739   EXPECT_NE(default_group, extra_group);
740 
741   EXPECT_FALSE(client_trial->group_reported_);
742   EXPECT_EQ(extra_group, client_trial->group());
743   EXPECT_TRUE(client_trial->group_reported_);
744   EXPECT_EQ(kExtraGroupName, client_trial->group_name());
745 }
746 
TEST_F(FieldTrialTest,SetForcedTurnFeatureOff)747 TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
748   const char kTrialName[] = "SetForcedTurnFeatureOff";
749   const char kExtraGroupName[] = "Extra";
750   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
751 
752   // Simulate a server-side (forced) config that turns the feature off when the
753   // original hard-coded config had it enabled.
754   scoped_refptr<FieldTrial> forced_trial =
755       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
756   forced_trial->AppendGroup(kExtraGroupName, 0);
757   forced_trial->SetForced();
758 
759   int default_group = -1;
760   scoped_refptr<FieldTrial> client_trial =
761       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
762   const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100);
763   EXPECT_NE(default_group, extra_group);
764 
765   EXPECT_FALSE(client_trial->group_reported_);
766   EXPECT_EQ(default_group, client_trial->group());
767   EXPECT_TRUE(client_trial->group_reported_);
768   EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
769 }
770 
TEST_F(FieldTrialTest,SetForcedChangeDefault_Default)771 TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
772   const char kTrialName[] = "SetForcedDefaultGroupChange";
773   const char kGroupAName[] = "A";
774   const char kGroupBName[] = "B";
775   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
776 
777   // Simulate a server-side (forced) config that switches which group is default
778   // and ensures that the non-forced code receives the correct group numbers.
779   scoped_refptr<FieldTrial> forced_trial =
780       CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
781   forced_trial->AppendGroup(kGroupBName, 100);
782   forced_trial->SetForced();
783 
784   int default_group = -1;
785   scoped_refptr<FieldTrial> client_trial =
786       CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
787   const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
788   EXPECT_NE(default_group, extra_group);
789 
790   EXPECT_FALSE(client_trial->group_reported_);
791   EXPECT_EQ(default_group, client_trial->group());
792   EXPECT_TRUE(client_trial->group_reported_);
793   EXPECT_EQ(kGroupBName, client_trial->group_name());
794 }
795 
TEST_F(FieldTrialTest,SetForcedChangeDefault_NonDefault)796 TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
797   const char kTrialName[] = "SetForcedDefaultGroupChange";
798   const char kGroupAName[] = "A";
799   const char kGroupBName[] = "B";
800   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
801 
802   // Simulate a server-side (forced) config that switches which group is default
803   // and ensures that the non-forced code receives the correct group numbers.
804   scoped_refptr<FieldTrial> forced_trial =
805       CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
806   forced_trial->AppendGroup(kGroupBName, 0);
807   forced_trial->SetForced();
808 
809   int default_group = -1;
810   scoped_refptr<FieldTrial> client_trial =
811       CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
812   const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
813   EXPECT_NE(default_group, extra_group);
814 
815   EXPECT_FALSE(client_trial->group_reported_);
816   EXPECT_EQ(extra_group, client_trial->group());
817   EXPECT_TRUE(client_trial->group_reported_);
818   EXPECT_EQ(kGroupAName, client_trial->group_name());
819 }
820 
TEST_F(FieldTrialTest,Observe)821 TEST_F(FieldTrialTest, Observe) {
822   const char kTrialName[] = "TrialToObserve1";
823   const char kSecondaryGroupName[] = "SecondaryGroup";
824 
825   TestFieldTrialObserver observer;
826   int default_group = -1;
827   scoped_refptr<FieldTrial> trial =
828       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
829   const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
830   const int chosen_group = trial->group();
831   EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
832 
833   RunLoop().RunUntilIdle();
834   EXPECT_EQ(kTrialName, observer.trial_name());
835   if (chosen_group == default_group)
836     EXPECT_EQ(kDefaultGroupName, observer.group_name());
837   else
838     EXPECT_EQ(kSecondaryGroupName, observer.group_name());
839 }
840 
TEST_F(FieldTrialTest,ObserveDisabled)841 TEST_F(FieldTrialTest, ObserveDisabled) {
842   const char kTrialName[] = "TrialToObserve2";
843 
844   TestFieldTrialObserver observer;
845   int default_group = -1;
846   scoped_refptr<FieldTrial> trial =
847       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
848   trial->AppendGroup("A", 25);
849   trial->AppendGroup("B", 25);
850   trial->AppendGroup("C", 25);
851   trial->Disable();
852 
853   // Observer shouldn't be notified of a disabled trial.
854   RunLoop().RunUntilIdle();
855   EXPECT_TRUE(observer.trial_name().empty());
856   EXPECT_TRUE(observer.group_name().empty());
857 
858   // Observer shouldn't be notified even after a |group()| call.
859   EXPECT_EQ(default_group, trial->group());
860   RunLoop().RunUntilIdle();
861   EXPECT_TRUE(observer.trial_name().empty());
862   EXPECT_TRUE(observer.group_name().empty());
863 }
864 
TEST_F(FieldTrialTest,ObserveForcedDisabled)865 TEST_F(FieldTrialTest, ObserveForcedDisabled) {
866   const char kTrialName[] = "TrialToObserve3";
867 
868   TestFieldTrialObserver observer;
869   int default_group = -1;
870   scoped_refptr<FieldTrial> trial =
871       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
872   trial->AppendGroup("A", 25);
873   trial->AppendGroup("B", 25);
874   trial->AppendGroup("C", 25);
875   trial->SetForced();
876   trial->Disable();
877 
878   // Observer shouldn't be notified of a disabled trial, even when forced.
879   RunLoop().RunUntilIdle();
880   EXPECT_TRUE(observer.trial_name().empty());
881   EXPECT_TRUE(observer.group_name().empty());
882 
883   // Observer shouldn't be notified even after a |group()| call.
884   EXPECT_EQ(default_group, trial->group());
885   RunLoop().RunUntilIdle();
886   EXPECT_TRUE(observer.trial_name().empty());
887   EXPECT_TRUE(observer.group_name().empty());
888 }
889 
TEST_F(FieldTrialTest,DisabledTrialNotActive)890 TEST_F(FieldTrialTest, DisabledTrialNotActive) {
891   const char kTrialName[] = "DisabledTrial";
892   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
893 
894   scoped_refptr<FieldTrial> trial =
895       CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
896   trial->AppendGroup("X", 50);
897   trial->Disable();
898 
899   // Ensure the trial is not listed as active.
900   FieldTrial::ActiveGroups active_groups;
901   FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
902   EXPECT_TRUE(active_groups.empty());
903 
904   // Ensure the trial is not listed in the |StatesToString()| result.
905   std::string states;
906   FieldTrialList::StatesToString(&states);
907   EXPECT_TRUE(states.empty());
908 }
909 
TEST_F(FieldTrialTest,ExpirationYearNotExpired)910 TEST_F(FieldTrialTest, ExpirationYearNotExpired) {
911   const char kTrialName[] = "NotExpired";
912   const char kGroupName[] = "Group2";
913   const int kProbability = 100;
914   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
915 
916   scoped_refptr<FieldTrial> trial =
917       CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL);
918   trial->AppendGroup(kGroupName, kProbability);
919   EXPECT_EQ(kGroupName, trial->group_name());
920 }
921 
TEST_F(FieldTrialTest,FloatBoundariesGiveEqualGroupSizes)922 TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
923   const int kBucketCount = 100;
924 
925   // Try each boundary value |i / 100.0| as the entropy value.
926   for (int i = 0; i < kBucketCount; ++i) {
927     const double entropy = i / static_cast<double>(kBucketCount);
928 
929     scoped_refptr<base::FieldTrial> trial(
930         new base::FieldTrial("test", kBucketCount, "default", entropy));
931     for (int j = 0; j < kBucketCount; ++j)
932       trial->AppendGroup(base::StringPrintf("%d", j), 1);
933 
934     EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
935   }
936 }
937 
TEST_F(FieldTrialTest,DoesNotSurpassTotalProbability)938 TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
939   const double kEntropyValue = 1.0 - 1e-9;
940   ASSERT_LT(kEntropyValue, 1.0);
941 
942   scoped_refptr<base::FieldTrial> trial(
943       new base::FieldTrial("test", 2, "default", kEntropyValue));
944   trial->AppendGroup("1", 1);
945   trial->AppendGroup("2", 1);
946 
947   EXPECT_EQ("2", trial->group_name());
948 }
949 
TEST_F(FieldTrialTest,CreateSimulatedFieldTrial)950 TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
951   const char kTrialName[] = "CreateSimulatedFieldTrial";
952   ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
953 
954   // Different cases to test, e.g. default vs. non default group being chosen.
955   struct {
956     double entropy_value;
957     const char* expected_group;
958   } test_cases[] = {
959     { 0.4, "A" },
960     { 0.85, "B" },
961     { 0.95, kDefaultGroupName },
962   };
963 
964   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
965     TestFieldTrialObserver observer;
966     scoped_refptr<FieldTrial> trial(
967        FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName,
968                                              test_cases[i].entropy_value));
969     trial->AppendGroup("A", 80);
970     trial->AppendGroup("B", 10);
971     EXPECT_EQ(test_cases[i].expected_group, trial->group_name());
972 
973     // Field trial shouldn't have been registered with the list.
974     EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
975     EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
976 
977     // Observer shouldn't have been notified.
978     RunLoop().RunUntilIdle();
979     EXPECT_TRUE(observer.trial_name().empty());
980 
981     // The trial shouldn't be in the active set of trials.
982     FieldTrial::ActiveGroups active_groups;
983     FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
984     EXPECT_TRUE(active_groups.empty());
985 
986     // The trial shouldn't be listed in the |StatesToString()| result.
987     std::string states;
988     FieldTrialList::StatesToString(&states);
989     EXPECT_TRUE(states.empty());
990   }
991 }
992 
993 }  // namespace base
994