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.
5 #include "base/metrics/field_trial.h"
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"
18 // Default group name used by several tests.
19 const char kDefaultGroupName
[] = "DefaultGroup";
21 // Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
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
);
34 Time last_year_time
= Time::NowFromSystemTime() - TimeDelta::FromDays(365);
35 Time::Exploded exploded
;
36 last_year_time
.LocalExplode(&exploded
);
40 // FieldTrialList::Observer implementation for testing.
41 class TestFieldTrialObserver
: public FieldTrialList::Observer
{
43 TestFieldTrialObserver() {
44 FieldTrialList::AddObserver(this);
47 virtual ~TestFieldTrialObserver() {
48 FieldTrialList::RemoveObserver(this);
51 virtual void OnFieldTrialGroupFinalized(const std::string
& trial
,
52 const std::string
& group
) OVERRIDE
{
57 const std::string
& trial_name() const { return trial_name_
; }
58 const std::string
& group_name() const { return group_name_
; }
61 std::string trial_name_
;
62 std::string group_name_
;
64 DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver
);
69 class FieldTrialTest
: public testing::Test
{
71 FieldTrialTest() : trial_list_(NULL
) {}
74 MessageLoop message_loop_
;
75 FieldTrialList trial_list_
;
78 // Test registration, and also check that destructors are called for trials
79 // (and that Valgrind doesn't catch us leaking).
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
));
86 FieldTrial
* trial1
= CreateFieldTrial(name1
, 10, "default name 1 test", NULL
);
87 EXPECT_EQ(FieldTrial::kNotFinalized
, trial1
->group_
);
88 EXPECT_EQ(name1
, trial1
->trial_name());
89 EXPECT_EQ("", trial1
->group_name_internal());
91 trial1
->AppendGroup(std::string(), 7);
93 EXPECT_EQ(trial1
, FieldTrialList::Find(name1
));
94 EXPECT_FALSE(FieldTrialList::Find(name2
));
96 FieldTrial
* trial2
= CreateFieldTrial(name2
, 10, "default name 2 test", NULL
);
97 EXPECT_EQ(FieldTrial::kNotFinalized
, trial2
->group_
);
98 EXPECT_EQ(name2
, trial2
->trial_name());
99 EXPECT_EQ("", trial2
->group_name_internal());
101 trial2
->AppendGroup("a first group", 7);
103 EXPECT_EQ(trial1
, FieldTrialList::Find(name1
));
104 EXPECT_EQ(trial2
, FieldTrialList::Find(name2
));
105 // Note: FieldTrialList should delete the objects at shutdown.
108 TEST_F(FieldTrialTest
, AbsoluteProbabilities
) {
109 char always_true
[] = " always true";
110 char default_always_true
[] = " default always true";
111 char always_false
[] = " always false";
112 char default_always_false
[] = " default always false";
113 for (int i
= 1; i
< 250; ++i
) {
114 // Try lots of names, by changing the first character of the name.
116 default_always_true
[0] = i
;
118 default_always_false
[0] = i
;
120 FieldTrial
* trial_true
=
121 CreateFieldTrial(always_true
, 10, default_always_true
, NULL
);
122 const std::string winner
= "TheWinner";
123 int winner_group
= trial_true
->AppendGroup(winner
, 10);
125 EXPECT_EQ(winner_group
, trial_true
->group());
126 EXPECT_EQ(winner
, trial_true
->group_name());
128 FieldTrial
* trial_false
=
129 CreateFieldTrial(always_false
, 10, default_always_false
, NULL
);
130 int loser_group
= trial_false
->AppendGroup("ALoser", 0);
132 EXPECT_NE(loser_group
, trial_false
->group());
136 TEST_F(FieldTrialTest
, RemainingProbability
) {
137 // First create a test that hasn't had a winner yet.
138 const std::string winner
= "Winner";
139 const std::string loser
= "Loser";
140 scoped_refptr
<FieldTrial
> trial
;
142 int default_group_number
= -1;
144 std::string name
= StringPrintf("trial%d", ++counter
);
145 trial
= CreateFieldTrial(name
, 10, winner
, &default_group_number
);
146 trial
->AppendGroup(loser
, 5); // 50% chance of not being chosen.
147 // If a group is not assigned, group_ will be kNotFinalized.
148 } while (trial
->group_
!= FieldTrial::kNotFinalized
);
150 // And that 'default' group (winner) should always win.
151 EXPECT_EQ(default_group_number
, trial
->group());
153 // And that winner should ALWAYS win.
154 EXPECT_EQ(winner
, trial
->group_name());
157 TEST_F(FieldTrialTest
, FiftyFiftyProbability
) {
158 // Check that even with small divisors, we have the proper probabilities, and
159 // all outcomes are possible. Since this is a 50-50 test, it should get both
160 // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
161 // with probability around 1 in 2^99).
162 bool first_winner
= false;
163 bool second_winner
= false;
166 std::string name
= base::StringPrintf("FiftyFifty%d", ++counter
);
167 std::string default_group_name
= base::StringPrintf("Default FiftyFifty%d",
169 FieldTrial
* trial
= CreateFieldTrial(name
, 2, default_group_name
, NULL
);
170 trial
->AppendGroup("first", 1); // 50% chance of being chosen.
171 // If group_ is kNotFinalized, then a group assignement hasn't been done.
172 if (trial
->group_
!= FieldTrial::kNotFinalized
) {
176 trial
->AppendGroup("second", 1); // Always chosen at this point.
177 EXPECT_NE(FieldTrial::kNotFinalized
, trial
->group());
178 second_winner
= true;
179 } while ((!second_winner
|| !first_winner
) && counter
< 100);
180 EXPECT_TRUE(second_winner
);
181 EXPECT_TRUE(first_winner
);
184 TEST_F(FieldTrialTest
, MiddleProbabilities
) {
185 char name
[] = " same name";
186 char default_group_name
[] = " default same name";
187 bool false_event_seen
= false;
188 bool true_event_seen
= false;
189 for (int i
= 1; i
< 250; ++i
) {
191 default_group_name
[0] = i
;
192 FieldTrial
* trial
= CreateFieldTrial(name
, 10, default_group_name
, NULL
);
193 int might_win
= trial
->AppendGroup("MightWin", 5);
195 if (trial
->group() == might_win
) {
196 true_event_seen
= true;
198 false_event_seen
= true;
200 if (false_event_seen
&& true_event_seen
)
201 return; // Successful test!!!
203 // Very surprising to get here. Probability should be around 1 in 2 ** 250.
204 // One of the following will fail.
205 EXPECT_TRUE(false_event_seen
);
206 EXPECT_TRUE(true_event_seen
);
209 TEST_F(FieldTrialTest
, OneWinner
) {
210 char name
[] = "Some name";
211 char default_group_name
[] = "Default some name";
214 int default_group_number
= -1;
216 CreateFieldTrial(name
, group_count
, default_group_name
, NULL
);
217 int winner_index(-2);
218 std::string winner_name
;
220 for (int i
= 1; i
<= group_count
; ++i
) {
221 int might_win
= trial
->AppendGroup(std::string(), 1);
223 // Because we keep appending groups, we want to see if the last group that
224 // was added has been assigned or not.
225 if (trial
->group_
== might_win
) {
226 EXPECT_EQ(-2, winner_index
);
227 winner_index
= might_win
;
228 StringAppendF(&winner_name
, "%d", might_win
);
229 EXPECT_EQ(winner_name
, trial
->group_name());
232 EXPECT_GE(winner_index
, 0);
233 // Since all groups cover the total probability, we should not have
234 // chosen the default group.
235 EXPECT_NE(trial
->group(), default_group_number
);
236 EXPECT_EQ(trial
->group(), winner_index
);
237 EXPECT_EQ(trial
->group_name(), winner_name
);
240 TEST_F(FieldTrialTest
, DisableProbability
) {
241 const std::string default_group_name
= "Default group";
242 const std::string loser
= "Loser";
243 const std::string name
= "Trial";
245 // Create a field trail that has expired.
246 int default_group_number
= -1;
247 FieldTrial
* trial
= FieldTrialList::FactoryGetFieldTrial(
248 name
, 1000000000, default_group_name
, GetLastYear(), 1, 1,
249 FieldTrial::SESSION_RANDOMIZED
,
250 &default_group_number
);
251 trial
->AppendGroup(loser
, 999999999); // 99.9999999% chance of being chosen.
253 // Because trial has expired, we should always be in the default group.
254 EXPECT_EQ(default_group_number
, trial
->group());
256 // And that default_group_name should ALWAYS win.
257 EXPECT_EQ(default_group_name
, trial
->group_name());
260 TEST_F(FieldTrialTest
, ActiveGroups
) {
261 std::string
no_group("No Group");
262 FieldTrial
* trial
= CreateFieldTrial(no_group
, 10, "Default", NULL
);
264 // There is no winner yet, so no NameGroupId should be returned.
265 FieldTrial::ActiveGroup active_group
;
266 EXPECT_FALSE(trial
->GetActiveGroup(&active_group
));
268 // Create a single winning group.
269 std::string
one_winner("One Winner");
270 trial
= CreateFieldTrial(one_winner
, 10, "Default", NULL
);
271 std::string
winner("Winner");
272 trial
->AppendGroup(winner
, 10);
273 EXPECT_FALSE(trial
->GetActiveGroup(&active_group
));
274 // Finalize the group selection by accessing the selected group.
276 EXPECT_TRUE(trial
->GetActiveGroup(&active_group
));
277 EXPECT_EQ(one_winner
, active_group
.trial_name
);
278 EXPECT_EQ(winner
, active_group
.group_name
);
280 std::string
multi_group("MultiGroup");
281 FieldTrial
* multi_group_trial
=
282 CreateFieldTrial(multi_group
, 9, "Default", NULL
);
284 multi_group_trial
->AppendGroup("Me", 3);
285 multi_group_trial
->AppendGroup("You", 3);
286 multi_group_trial
->AppendGroup("Them", 3);
287 EXPECT_FALSE(multi_group_trial
->GetActiveGroup(&active_group
));
288 // Finalize the group selection by accessing the selected group.
289 multi_group_trial
->group();
290 EXPECT_TRUE(multi_group_trial
->GetActiveGroup(&active_group
));
291 EXPECT_EQ(multi_group
, active_group
.trial_name
);
292 EXPECT_EQ(multi_group_trial
->group_name(), active_group
.group_name
);
294 // Now check if the list is built properly...
295 FieldTrial::ActiveGroups active_groups
;
296 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
297 EXPECT_EQ(2U, active_groups
.size());
298 for (size_t i
= 0; i
< active_groups
.size(); ++i
) {
299 // Order is not guaranteed, so check all values.
300 EXPECT_NE(no_group
, active_groups
[i
].trial_name
);
301 EXPECT_TRUE(one_winner
!= active_groups
[i
].trial_name
||
302 winner
== active_groups
[i
].group_name
);
303 EXPECT_TRUE(multi_group
!= active_groups
[i
].trial_name
||
304 multi_group_trial
->group_name() == active_groups
[i
].group_name
);
308 TEST_F(FieldTrialTest
, ActiveGroupsNotFinalized
) {
309 const char kTrialName
[] = "TestTrial";
310 const char kSecondaryGroupName
[] = "SecondaryGroup";
312 int default_group
= -1;
314 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
315 const int secondary_group
= trial
->AppendGroup(kSecondaryGroupName
, 50);
317 // Before |group()| is called, |GetActiveGroup()| should return false.
318 FieldTrial::ActiveGroup active_group
;
319 EXPECT_FALSE(trial
->GetActiveGroup(&active_group
));
321 // |GetActiveFieldTrialGroups()| should also not include the trial.
322 FieldTrial::ActiveGroups active_groups
;
323 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
324 EXPECT_TRUE(active_groups
.empty());
326 // After |group()| has been called, both APIs should succeed.
327 const int chosen_group
= trial
->group();
328 EXPECT_TRUE(chosen_group
== default_group
|| chosen_group
== secondary_group
);
330 EXPECT_TRUE(trial
->GetActiveGroup(&active_group
));
331 EXPECT_EQ(kTrialName
, active_group
.trial_name
);
332 if (chosen_group
== default_group
)
333 EXPECT_EQ(kDefaultGroupName
, active_group
.group_name
);
335 EXPECT_EQ(kSecondaryGroupName
, active_group
.group_name
);
337 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
338 ASSERT_EQ(1U, active_groups
.size());
339 EXPECT_EQ(kTrialName
, active_groups
[0].trial_name
);
340 EXPECT_EQ(active_group
.group_name
, active_groups
[0].group_name
);
343 TEST_F(FieldTrialTest
, Save
) {
344 std::string save_string
;
347 CreateFieldTrial("Some name", 10, "Default some name", NULL
);
348 // There is no winner yet, so no textual group name is associated with trial.
349 // In this case, the trial should not be included.
350 EXPECT_EQ("", trial
->group_name_internal());
351 FieldTrialList::StatesToString(&save_string
);
352 EXPECT_EQ("", save_string
);
355 // Create a winning group.
356 trial
->AppendGroup("Winner", 10);
357 // Finalize the group selection by accessing the selected group.
359 FieldTrialList::StatesToString(&save_string
);
360 EXPECT_EQ("Some name/Winner/", save_string
);
363 // Create a second trial and winning group.
364 FieldTrial
* trial2
= CreateFieldTrial("xxx", 10, "Default xxx", NULL
);
365 trial2
->AppendGroup("yyyy", 10);
366 // Finalize the group selection by accessing the selected group.
369 FieldTrialList::StatesToString(&save_string
);
370 // We assume names are alphabetized... though this is not critical.
371 EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string
);
374 // Create a third trial with only the default group.
375 FieldTrial
* trial3
= CreateFieldTrial("zzz", 10, "default", NULL
);
376 // Finalize the group selection by accessing the selected group.
379 FieldTrialList::StatesToString(&save_string
);
380 EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string
);
383 TEST_F(FieldTrialTest
, Restore
) {
384 ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
385 ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
387 FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/",
388 FieldTrialList::DONT_ACTIVATE_TRIALS
,
389 std::set
<std::string
>());
391 FieldTrial
* trial
= FieldTrialList::Find("Some_name");
392 ASSERT_NE(static_cast<FieldTrial
*>(NULL
), trial
);
393 EXPECT_EQ("Winner", trial
->group_name());
394 EXPECT_EQ("Some_name", trial
->trial_name());
396 trial
= FieldTrialList::Find("xxx");
397 ASSERT_NE(static_cast<FieldTrial
*>(NULL
), trial
);
398 EXPECT_EQ("yyyy", trial
->group_name());
399 EXPECT_EQ("xxx", trial
->trial_name());
402 TEST_F(FieldTrialTest
, BogusRestore
) {
403 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
404 "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS
,
405 std::set
<std::string
>()));
406 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
407 "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS
,
408 std::set
<std::string
>()));
409 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
410 "MissingFinalSlash/gname", FieldTrialList::DONT_ACTIVATE_TRIALS
,
411 std::set
<std::string
>()));
412 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
413 "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS
,
414 std::set
<std::string
>()));
417 TEST_F(FieldTrialTest
, DuplicateRestore
) {
418 FieldTrial
* trial
= CreateFieldTrial("Some name", 10, "Default", NULL
);
419 trial
->AppendGroup("Winner", 10);
420 // Finalize the group selection by accessing the selected group.
422 std::string save_string
;
423 FieldTrialList::StatesToString(&save_string
);
424 EXPECT_EQ("Some name/Winner/", save_string
);
426 // It is OK if we redundantly specify a winner.
427 EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
428 save_string
, FieldTrialList::DONT_ACTIVATE_TRIALS
,
429 std::set
<std::string
>()));
431 // But it is an error to try to change to a different winner.
432 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
433 "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS
,
434 std::set
<std::string
>()));
437 TEST_F(FieldTrialTest
, CreateTrialsFromStringActive
) {
438 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
439 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
440 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
441 "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS
,
442 std::set
<std::string
>()));
444 FieldTrial::ActiveGroups active_groups
;
445 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
446 ASSERT_EQ(2U, active_groups
.size());
447 EXPECT_EQ("Abc", active_groups
[0].trial_name
);
448 EXPECT_EQ("def", active_groups
[0].group_name
);
449 EXPECT_EQ("Xyz", active_groups
[1].trial_name
);
450 EXPECT_EQ("zyx", active_groups
[1].group_name
);
453 TEST_F(FieldTrialTest
, CreateTrialsFromStringNotActive
) {
454 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
455 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
456 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
457 "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS
,
458 std::set
<std::string
>()));
460 FieldTrial::ActiveGroups active_groups
;
461 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
462 ASSERT_TRUE(active_groups
.empty());
464 // Check that the values still get returned and querying them activates them.
465 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
466 EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
468 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
469 ASSERT_EQ(2U, active_groups
.size());
470 EXPECT_EQ("Abc", active_groups
[0].trial_name
);
471 EXPECT_EQ("def", active_groups
[0].group_name
);
472 EXPECT_EQ("Xyz", active_groups
[1].trial_name
);
473 EXPECT_EQ("zyx", active_groups
[1].group_name
);
476 TEST_F(FieldTrialTest
, CreateTrialsFromStringActiveObserver
) {
477 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
479 TestFieldTrialObserver observer
;
480 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
481 "Abc/def/", FieldTrialList::ACTIVATE_TRIALS
, std::set
<std::string
>()));
483 RunLoop().RunUntilIdle();
484 EXPECT_EQ("Abc", observer
.trial_name());
485 EXPECT_EQ("def", observer
.group_name());
488 TEST_F(FieldTrialTest
, CreateTrialsFromStringNotActiveObserver
) {
489 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
491 TestFieldTrialObserver observer
;
492 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
493 "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS
,
494 std::set
<std::string
>()));
495 RunLoop().RunUntilIdle();
496 // Observer shouldn't be notified.
497 EXPECT_TRUE(observer
.trial_name().empty());
499 // Check that the values still get returned and querying them activates them.
500 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
502 RunLoop().RunUntilIdle();
503 EXPECT_EQ("Abc", observer
.trial_name());
504 EXPECT_EQ("def", observer
.group_name());
507 TEST_F(FieldTrialTest
, CreateTrialsFromStringWithIgnoredFieldTrials
) {
508 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
509 ASSERT_FALSE(FieldTrialList::TrialExists("Foo"));
510 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
511 ASSERT_FALSE(FieldTrialList::TrialExists("Bar"));
512 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
514 std::set
<std::string
> ignored_trial_names
;
515 ignored_trial_names
.insert("Unaccepted1");
516 ignored_trial_names
.insert("Unaccepted2");
517 ignored_trial_names
.insert("Unaccepted3");
519 FieldTrialList::CreateTrialsFromString(
520 "Unaccepted1/Unaccepted1_name/"
522 "Unaccepted2/Unaccepted2_name/"
524 "Unaccepted3/Unaccepted3_name/",
525 FieldTrialList::DONT_ACTIVATE_TRIALS
,
526 ignored_trial_names
);
528 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
529 EXPECT_TRUE(FieldTrialList::TrialExists("Foo"));
530 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
531 EXPECT_TRUE(FieldTrialList::TrialExists("Bar"));
532 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
534 FieldTrial::ActiveGroups active_groups
;
535 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
536 EXPECT_TRUE(active_groups
.empty());
538 FieldTrial
* trial
= FieldTrialList::Find("Foo");
539 ASSERT_NE(static_cast<FieldTrial
*>(NULL
), trial
);
540 EXPECT_EQ("Foo", trial
->trial_name());
541 EXPECT_EQ("Foo_name", trial
->group_name());
543 trial
= FieldTrialList::Find("Bar");
544 ASSERT_NE(static_cast<FieldTrial
*>(NULL
), trial
);
545 EXPECT_EQ("Bar", trial
->trial_name());
546 EXPECT_EQ("Bar_name", trial
->group_name());
549 TEST_F(FieldTrialTest
, CreateFieldTrial
) {
550 ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
552 FieldTrialList::CreateFieldTrial("Some_name", "Winner");
554 FieldTrial
* trial
= FieldTrialList::Find("Some_name");
555 ASSERT_NE(static_cast<FieldTrial
*>(NULL
), trial
);
556 EXPECT_EQ("Winner", trial
->group_name());
557 EXPECT_EQ("Some_name", trial
->trial_name());
560 TEST_F(FieldTrialTest
, CreateFieldTrialIsNotActive
) {
561 const char kTrialName
[] = "CreateFieldTrialIsActiveTrial";
562 const char kWinnerGroup
[] = "Winner";
563 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
564 FieldTrialList::CreateFieldTrial(kTrialName
, kWinnerGroup
);
566 FieldTrial::ActiveGroups active_groups
;
567 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
568 EXPECT_TRUE(active_groups
.empty());
571 TEST_F(FieldTrialTest
, DuplicateFieldTrial
) {
572 FieldTrial
* trial
= CreateFieldTrial("Some_name", 10, "Default", NULL
);
573 trial
->AppendGroup("Winner", 10);
575 // It is OK if we redundantly specify a winner.
576 FieldTrial
* trial1
= FieldTrialList::CreateFieldTrial("Some_name", "Winner");
577 EXPECT_TRUE(trial1
!= NULL
);
579 // But it is an error to try to change to a different winner.
580 FieldTrial
* trial2
= FieldTrialList::CreateFieldTrial("Some_name", "Loser");
581 EXPECT_TRUE(trial2
== NULL
);
584 TEST_F(FieldTrialTest
, DisableImmediately
) {
585 int default_group_number
= -1;
587 CreateFieldTrial("trial", 100, "default", &default_group_number
);
589 ASSERT_EQ("default", trial
->group_name());
590 ASSERT_EQ(default_group_number
, trial
->group());
593 TEST_F(FieldTrialTest
, DisableAfterInitialization
) {
594 FieldTrial
* trial
= CreateFieldTrial("trial", 100, "default", NULL
);
595 trial
->AppendGroup("non_default", 100);
597 ASSERT_EQ("default", trial
->group_name());
600 TEST_F(FieldTrialTest
, ForcedFieldTrials
) {
601 // Validate we keep the forced choice.
602 FieldTrial
* forced_trial
= FieldTrialList::CreateFieldTrial("Use the",
604 EXPECT_STREQ("Force", forced_trial
->group_name().c_str());
606 int default_group_number
= -1;
607 FieldTrial
* factory_trial
=
608 CreateFieldTrial("Use the", 1000, "default", &default_group_number
);
609 EXPECT_EQ(factory_trial
, forced_trial
);
611 int chosen_group
= factory_trial
->AppendGroup("Force", 100);
612 EXPECT_EQ(chosen_group
, factory_trial
->group());
613 int not_chosen_group
= factory_trial
->AppendGroup("Dark Side", 100);
614 EXPECT_NE(chosen_group
, not_chosen_group
);
616 // Since we didn't force the default group, we should not be returned the
617 // chosen group as the default group.
618 EXPECT_NE(default_group_number
, chosen_group
);
619 int new_group
= factory_trial
->AppendGroup("Duck Tape", 800);
620 EXPECT_NE(chosen_group
, new_group
);
621 // The new group should not be the default group either.
622 EXPECT_NE(default_group_number
, new_group
);
625 TEST_F(FieldTrialTest
, ForcedFieldTrialsDefaultGroup
) {
626 // Forcing the default should use the proper group ID.
627 FieldTrial
* forced_trial
= FieldTrialList::CreateFieldTrial("Trial Name",
629 int default_group_number
= -1;
630 FieldTrial
* factory_trial
=
631 CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number
);
632 EXPECT_EQ(forced_trial
, factory_trial
);
634 int other_group
= factory_trial
->AppendGroup("Not Default", 100);
635 EXPECT_STREQ("Default", factory_trial
->group_name().c_str());
636 EXPECT_EQ(default_group_number
, factory_trial
->group());
637 EXPECT_NE(other_group
, factory_trial
->group());
639 int new_other_group
= factory_trial
->AppendGroup("Not Default Either", 800);
640 EXPECT_NE(new_other_group
, factory_trial
->group());
643 TEST_F(FieldTrialTest
, SetForced
) {
644 // Start by setting a trial for which we ensure a winner...
645 int default_group_number
= -1;
646 FieldTrial
* forced_trial
=
647 CreateFieldTrial("Use the", 1, "default", &default_group_number
);
648 EXPECT_EQ(forced_trial
, forced_trial
);
650 int forced_group
= forced_trial
->AppendGroup("Force", 1);
651 EXPECT_EQ(forced_group
, forced_trial
->group());
654 forced_trial
->SetForced();
656 // Now try to set it up differently as a hard coded registration would.
657 FieldTrial
* hard_coded_trial
=
658 CreateFieldTrial("Use the", 1, "default", &default_group_number
);
659 EXPECT_EQ(hard_coded_trial
, forced_trial
);
661 int would_lose_group
= hard_coded_trial
->AppendGroup("Force", 0);
662 EXPECT_EQ(forced_group
, hard_coded_trial
->group());
663 EXPECT_EQ(forced_group
, would_lose_group
);
665 // Same thing if we would have done it to win again.
666 FieldTrial
* other_hard_coded_trial
=
667 CreateFieldTrial("Use the", 1, "default", &default_group_number
);
668 EXPECT_EQ(other_hard_coded_trial
, forced_trial
);
670 int would_win_group
= other_hard_coded_trial
->AppendGroup("Force", 1);
671 EXPECT_EQ(forced_group
, other_hard_coded_trial
->group());
672 EXPECT_EQ(forced_group
, would_win_group
);
675 TEST_F(FieldTrialTest
, SetForcedDefaultOnly
) {
676 const char kTrialName
[] = "SetForcedDefaultOnly";
677 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
679 int default_group
= -1;
681 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
684 trial
= CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, NULL
);
685 EXPECT_EQ(default_group
, trial
->group());
686 EXPECT_EQ(kDefaultGroupName
, trial
->group_name());
689 TEST_F(FieldTrialTest
, SetForcedDefaultWithExtraGroup
) {
690 const char kTrialName
[] = "SetForcedDefaultWithExtraGroup";
691 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
693 int default_group
= -1;
695 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
698 trial
= CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, NULL
);
699 const int extra_group
= trial
->AppendGroup("Extra", 100);
700 EXPECT_EQ(default_group
, trial
->group());
701 EXPECT_NE(extra_group
, trial
->group());
702 EXPECT_EQ(kDefaultGroupName
, trial
->group_name());
705 TEST_F(FieldTrialTest
, SetForcedTurnFeatureOn
) {
706 const char kTrialName
[] = "SetForcedTurnFeatureOn";
707 const char kExtraGroupName
[] = "Extra";
708 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
710 // Simulate a server-side (forced) config that turns the feature on when the
711 // original hard-coded config had it disabled.
712 FieldTrial
* forced_trial
=
713 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, NULL
);
714 forced_trial
->AppendGroup(kExtraGroupName
, 100);
715 forced_trial
->SetForced();
717 int default_group
= -1;
718 FieldTrial
* client_trial
=
719 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
720 const int extra_group
= client_trial
->AppendGroup(kExtraGroupName
, 0);
721 EXPECT_NE(default_group
, extra_group
);
723 EXPECT_FALSE(client_trial
->group_reported_
);
724 EXPECT_EQ(extra_group
, client_trial
->group());
725 EXPECT_TRUE(client_trial
->group_reported_
);
726 EXPECT_EQ(kExtraGroupName
, client_trial
->group_name());
729 TEST_F(FieldTrialTest
, SetForcedTurnFeatureOff
) {
730 const char kTrialName
[] = "SetForcedTurnFeatureOff";
731 const char kExtraGroupName
[] = "Extra";
732 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
734 // Simulate a server-side (forced) config that turns the feature off when the
735 // original hard-coded config had it enabled.
736 FieldTrial
* forced_trial
=
737 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, NULL
);
738 forced_trial
->AppendGroup(kExtraGroupName
, 0);
739 forced_trial
->SetForced();
741 int default_group
= -1;
742 FieldTrial
* client_trial
=
743 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
744 const int extra_group
= client_trial
->AppendGroup(kExtraGroupName
, 100);
745 EXPECT_NE(default_group
, extra_group
);
747 EXPECT_FALSE(client_trial
->group_reported_
);
748 EXPECT_EQ(default_group
, client_trial
->group());
749 EXPECT_TRUE(client_trial
->group_reported_
);
750 EXPECT_EQ(kDefaultGroupName
, client_trial
->group_name());
753 TEST_F(FieldTrialTest
, SetForcedChangeDefault_Default
) {
754 const char kTrialName
[] = "SetForcedDefaultGroupChange";
755 const char kGroupAName
[] = "A";
756 const char kGroupBName
[] = "B";
757 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
759 // Simulate a server-side (forced) config that switches which group is default
760 // and ensures that the non-forced code receives the correct group numbers.
761 FieldTrial
* forced_trial
=
762 CreateFieldTrial(kTrialName
, 100, kGroupAName
, NULL
);
763 forced_trial
->AppendGroup(kGroupBName
, 100);
764 forced_trial
->SetForced();
766 int default_group
= -1;
767 FieldTrial
* client_trial
=
768 CreateFieldTrial(kTrialName
, 100, kGroupBName
, &default_group
);
769 const int extra_group
= client_trial
->AppendGroup(kGroupAName
, 50);
770 EXPECT_NE(default_group
, extra_group
);
772 EXPECT_FALSE(client_trial
->group_reported_
);
773 EXPECT_EQ(default_group
, client_trial
->group());
774 EXPECT_TRUE(client_trial
->group_reported_
);
775 EXPECT_EQ(kGroupBName
, client_trial
->group_name());
778 TEST_F(FieldTrialTest
, SetForcedChangeDefault_NonDefault
) {
779 const char kTrialName
[] = "SetForcedDefaultGroupChange";
780 const char kGroupAName
[] = "A";
781 const char kGroupBName
[] = "B";
782 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
784 // Simulate a server-side (forced) config that switches which group is default
785 // and ensures that the non-forced code receives the correct group numbers.
786 FieldTrial
* forced_trial
=
787 CreateFieldTrial(kTrialName
, 100, kGroupAName
, NULL
);
788 forced_trial
->AppendGroup(kGroupBName
, 0);
789 forced_trial
->SetForced();
791 int default_group
= -1;
792 FieldTrial
* client_trial
=
793 CreateFieldTrial(kTrialName
, 100, kGroupBName
, &default_group
);
794 const int extra_group
= client_trial
->AppendGroup(kGroupAName
, 50);
795 EXPECT_NE(default_group
, extra_group
);
797 EXPECT_FALSE(client_trial
->group_reported_
);
798 EXPECT_EQ(extra_group
, client_trial
->group());
799 EXPECT_TRUE(client_trial
->group_reported_
);
800 EXPECT_EQ(kGroupAName
, client_trial
->group_name());
803 TEST_F(FieldTrialTest
, Observe
) {
804 const char kTrialName
[] = "TrialToObserve1";
805 const char kSecondaryGroupName
[] = "SecondaryGroup";
807 TestFieldTrialObserver observer
;
808 int default_group
= -1;
810 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
811 const int secondary_group
= trial
->AppendGroup(kSecondaryGroupName
, 50);
812 const int chosen_group
= trial
->group();
813 EXPECT_TRUE(chosen_group
== default_group
|| chosen_group
== secondary_group
);
815 RunLoop().RunUntilIdle();
816 EXPECT_EQ(kTrialName
, observer
.trial_name());
817 if (chosen_group
== default_group
)
818 EXPECT_EQ(kDefaultGroupName
, observer
.group_name());
820 EXPECT_EQ(kSecondaryGroupName
, observer
.group_name());
823 TEST_F(FieldTrialTest
, ObserveDisabled
) {
824 const char kTrialName
[] = "TrialToObserve2";
826 TestFieldTrialObserver observer
;
827 int default_group
= -1;
829 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
830 trial
->AppendGroup("A", 25);
831 trial
->AppendGroup("B", 25);
832 trial
->AppendGroup("C", 25);
835 // Observer shouldn't be notified of a disabled trial.
836 RunLoop().RunUntilIdle();
837 EXPECT_TRUE(observer
.trial_name().empty());
838 EXPECT_TRUE(observer
.group_name().empty());
840 // Observer shouldn't be notified even after a |group()| call.
841 EXPECT_EQ(default_group
, trial
->group());
842 RunLoop().RunUntilIdle();
843 EXPECT_TRUE(observer
.trial_name().empty());
844 EXPECT_TRUE(observer
.group_name().empty());
847 TEST_F(FieldTrialTest
, ObserveForcedDisabled
) {
848 const char kTrialName
[] = "TrialToObserve3";
850 TestFieldTrialObserver observer
;
851 int default_group
= -1;
853 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, &default_group
);
854 trial
->AppendGroup("A", 25);
855 trial
->AppendGroup("B", 25);
856 trial
->AppendGroup("C", 25);
860 // Observer shouldn't be notified of a disabled trial, even when forced.
861 RunLoop().RunUntilIdle();
862 EXPECT_TRUE(observer
.trial_name().empty());
863 EXPECT_TRUE(observer
.group_name().empty());
865 // Observer shouldn't be notified even after a |group()| call.
866 EXPECT_EQ(default_group
, trial
->group());
867 RunLoop().RunUntilIdle();
868 EXPECT_TRUE(observer
.trial_name().empty());
869 EXPECT_TRUE(observer
.group_name().empty());
872 TEST_F(FieldTrialTest
, DisabledTrialNotActive
) {
873 const char kTrialName
[] = "DisabledTrial";
874 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
877 CreateFieldTrial(kTrialName
, 100, kDefaultGroupName
, NULL
);
878 trial
->AppendGroup("X", 50);
881 // Ensure the trial is not listed as active.
882 FieldTrial::ActiveGroups active_groups
;
883 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
884 EXPECT_TRUE(active_groups
.empty());
886 // Ensure the trial is not listed in the |StatesToString()| result.
888 FieldTrialList::StatesToString(&states
);
889 EXPECT_TRUE(states
.empty());
892 TEST_F(FieldTrialTest
, ExpirationYearNotExpired
) {
893 const char kTrialName
[] = "NotExpired";
894 const char kGroupName
[] = "Group2";
895 const int kProbability
= 100;
896 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
899 CreateFieldTrial(kTrialName
, kProbability
, kDefaultGroupName
, NULL
);
900 trial
->AppendGroup(kGroupName
, kProbability
);
901 EXPECT_EQ(kGroupName
, trial
->group_name());
904 TEST_F(FieldTrialTest
, FloatBoundariesGiveEqualGroupSizes
) {
905 const int kBucketCount
= 100;
907 // Try each boundary value |i / 100.0| as the entropy value.
908 for (int i
= 0; i
< kBucketCount
; ++i
) {
909 const double entropy
= i
/ static_cast<double>(kBucketCount
);
911 scoped_refptr
<base::FieldTrial
> trial(
912 new base::FieldTrial("test", kBucketCount
, "default", entropy
));
913 for (int j
= 0; j
< kBucketCount
; ++j
)
914 trial
->AppendGroup(base::StringPrintf("%d", j
), 1);
916 EXPECT_EQ(base::StringPrintf("%d", i
), trial
->group_name());
920 TEST_F(FieldTrialTest
, DoesNotSurpassTotalProbability
) {
921 const double kEntropyValue
= 1.0 - 1e-9;
922 ASSERT_LT(kEntropyValue
, 1.0);
924 scoped_refptr
<base::FieldTrial
> trial(
925 new base::FieldTrial("test", 2, "default", kEntropyValue
));
926 trial
->AppendGroup("1", 1);
927 trial
->AppendGroup("2", 1);
929 EXPECT_EQ("2", trial
->group_name());
932 TEST_F(FieldTrialTest
, CreateSimulatedFieldTrial
) {
933 const char kTrialName
[] = "CreateSimulatedFieldTrial";
934 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName
));
936 // Different cases to test, e.g. default vs. non default group being chosen.
938 double entropy_value
;
939 const char* expected_group
;
943 { 0.95, kDefaultGroupName
},
946 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
947 TestFieldTrialObserver observer
;
948 scoped_refptr
<FieldTrial
> trial(
949 FieldTrial::CreateSimulatedFieldTrial(kTrialName
, 100, kDefaultGroupName
,
950 test_cases
[i
].entropy_value
));
951 trial
->AppendGroup("A", 80);
952 trial
->AppendGroup("B", 10);
953 EXPECT_EQ(test_cases
[i
].expected_group
, trial
->group_name());
955 // Field trial shouldn't have been registered with the list.
956 EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName
));
957 EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
959 // Observer shouldn't have been notified.
960 RunLoop().RunUntilIdle();
961 EXPECT_TRUE(observer
.trial_name().empty());
963 // The trial shouldn't be in the active set of trials.
964 FieldTrial::ActiveGroups active_groups
;
965 FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
966 EXPECT_TRUE(active_groups
.empty());
968 // The trial shouldn't be listed in the |StatesToString()| result.
970 FieldTrialList::StatesToString(&states
);
971 EXPECT_TRUE(states
.empty());