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 <stddef.h>
8
9 #include "base/base_switches.h"
10 #include "base/build_time.h"
11 #include "base/feature_list.h"
12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/field_trial_param_associator.h"
16 #include "base/rand_util.h"
17 #include "base/run_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/test/gtest_util.h"
21 #include "base/test/mock_entropy_provider.h"
22 #include "base/test/scoped_feature_list.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace base {
26
27 namespace {
28
29 // Default group name used by several tests.
30 const char kDefaultGroupName[] = "DefaultGroup";
31
32 // 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)33 scoped_refptr<base::FieldTrial> CreateFieldTrial(
34 const std::string& trial_name,
35 int total_probability,
36 const std::string& default_group_name,
37 int* default_group_number) {
38 return FieldTrialList::FactoryGetFieldTrial(
39 trial_name, total_probability, default_group_name,
40 base::FieldTrialList::kNoExpirationYear, 1, 1,
41 base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
42 }
43
OneYearBeforeBuildTime()44 int OneYearBeforeBuildTime() {
45 Time one_year_before_build_time = GetBuildTime() - TimeDelta::FromDays(365);
46 Time::Exploded exploded;
47 one_year_before_build_time.LocalExplode(&exploded);
48 return exploded.year;
49 }
50
51 // FieldTrialList::Observer implementation for testing.
52 class TestFieldTrialObserver : public FieldTrialList::Observer {
53 public:
TestFieldTrialObserver()54 TestFieldTrialObserver() {
55 FieldTrialList::AddObserver(this);
56 }
57
~TestFieldTrialObserver()58 ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); }
59
OnFieldTrialGroupFinalized(const std::string & trial,const std::string & group)60 void OnFieldTrialGroupFinalized(const std::string& trial,
61 const std::string& group) override {
62 trial_name_ = trial;
63 group_name_ = group;
64 }
65
trial_name() const66 const std::string& trial_name() const { return trial_name_; }
group_name() const67 const std::string& group_name() const { return group_name_; }
68
69 private:
70 std::string trial_name_;
71 std::string group_name_;
72
73 DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver);
74 };
75
76 } // namespace
77
78 class FieldTrialTest : public testing::Test {
79 public:
FieldTrialTest()80 FieldTrialTest() : trial_list_(NULL) {}
81
82 private:
83 MessageLoop message_loop_;
84 FieldTrialList trial_list_;
85
86 DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
87 };
88
89 // Test registration, and also check that destructors are called for trials
90 // (and that Valgrind doesn't catch us leaking).
TEST_F(FieldTrialTest,Registration)91 TEST_F(FieldTrialTest, Registration) {
92 const char name1[] = "name 1 test";
93 const char name2[] = "name 2 test";
94 EXPECT_FALSE(FieldTrialList::Find(name1));
95 EXPECT_FALSE(FieldTrialList::Find(name2));
96
97 scoped_refptr<FieldTrial> trial1 =
98 CreateFieldTrial(name1, 10, "default name 1 test", NULL);
99 EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
100 EXPECT_EQ(name1, trial1->trial_name());
101 EXPECT_EQ("", trial1->group_name_internal());
102
103 trial1->AppendGroup(std::string(), 7);
104
105 EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
106 EXPECT_FALSE(FieldTrialList::Find(name2));
107
108 scoped_refptr<FieldTrial> trial2 =
109 CreateFieldTrial(name2, 10, "default name 2 test", NULL);
110 EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
111 EXPECT_EQ(name2, trial2->trial_name());
112 EXPECT_EQ("", trial2->group_name_internal());
113
114 trial2->AppendGroup("a first group", 7);
115
116 EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
117 EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
118 // Note: FieldTrialList should delete the objects at shutdown.
119 }
120
TEST_F(FieldTrialTest,AbsoluteProbabilities)121 TEST_F(FieldTrialTest, AbsoluteProbabilities) {
122 char always_true[] = " always true";
123 char default_always_true[] = " default always true";
124 char always_false[] = " always false";
125 char default_always_false[] = " default always false";
126 for (int i = 1; i < 250; ++i) {
127 // Try lots of names, by changing the first character of the name.
128 char c = static_cast<char>(i);
129 always_true[0] = c;
130 default_always_true[0] = c;
131 always_false[0] = c;
132 default_always_false[0] = c;
133
134 scoped_refptr<FieldTrial> trial_true =
135 CreateFieldTrial(always_true, 10, default_always_true, NULL);
136 const std::string winner = "TheWinner";
137 int winner_group = trial_true->AppendGroup(winner, 10);
138
139 EXPECT_EQ(winner_group, trial_true->group());
140 EXPECT_EQ(winner, trial_true->group_name());
141
142 scoped_refptr<FieldTrial> trial_false =
143 CreateFieldTrial(always_false, 10, default_always_false, NULL);
144 int loser_group = trial_false->AppendGroup("ALoser", 0);
145
146 EXPECT_NE(loser_group, trial_false->group());
147 }
148 }
149
TEST_F(FieldTrialTest,RemainingProbability)150 TEST_F(FieldTrialTest, RemainingProbability) {
151 // First create a test that hasn't had a winner yet.
152 const std::string winner = "Winner";
153 const std::string loser = "Loser";
154 scoped_refptr<FieldTrial> trial;
155 int counter = 0;
156 int default_group_number = -1;
157 do {
158 std::string name = StringPrintf("trial%d", ++counter);
159 trial = CreateFieldTrial(name, 10, winner, &default_group_number);
160 trial->AppendGroup(loser, 5); // 50% chance of not being chosen.
161 // If a group is not assigned, group_ will be kNotFinalized.
162 } while (trial->group_ != FieldTrial::kNotFinalized);
163
164 // And that 'default' group (winner) should always win.
165 EXPECT_EQ(default_group_number, trial->group());
166
167 // And that winner should ALWAYS win.
168 EXPECT_EQ(winner, trial->group_name());
169 }
170
TEST_F(FieldTrialTest,FiftyFiftyProbability)171 TEST_F(FieldTrialTest, FiftyFiftyProbability) {
172 // Check that even with small divisors, we have the proper probabilities, and
173 // all outcomes are possible. Since this is a 50-50 test, it should get both
174 // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
175 // with probability around 1 in 2^99).
176 bool first_winner = false;
177 bool second_winner = false;
178 int counter = 0;
179 do {
180 std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
181 std::string default_group_name = base::StringPrintf("Default FiftyFifty%d",
182 ++counter);
183 scoped_refptr<FieldTrial> trial =
184 CreateFieldTrial(name, 2, default_group_name, NULL);
185 trial->AppendGroup("first", 1); // 50% chance of being chosen.
186 // If group_ is kNotFinalized, then a group assignement hasn't been done.
187 if (trial->group_ != FieldTrial::kNotFinalized) {
188 first_winner = true;
189 continue;
190 }
191 trial->AppendGroup("second", 1); // Always chosen at this point.
192 EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
193 second_winner = true;
194 } while ((!second_winner || !first_winner) && counter < 100);
195 EXPECT_TRUE(second_winner);
196 EXPECT_TRUE(first_winner);
197 }
198
TEST_F(FieldTrialTest,MiddleProbabilities)199 TEST_F(FieldTrialTest, MiddleProbabilities) {
200 char name[] = " same name";
201 char default_group_name[] = " default same name";
202 bool false_event_seen = false;
203 bool true_event_seen = false;
204 for (int i = 1; i < 250; ++i) {
205 char c = static_cast<char>(i);
206 name[0] = c;
207 default_group_name[0] = c;
208 scoped_refptr<FieldTrial> trial =
209 CreateFieldTrial(name, 10, default_group_name, NULL);
210 int might_win = trial->AppendGroup("MightWin", 5);
211
212 if (trial->group() == might_win) {
213 true_event_seen = true;
214 } else {
215 false_event_seen = true;
216 }
217 if (false_event_seen && true_event_seen)
218 return; // Successful test!!!
219 }
220 // Very surprising to get here. Probability should be around 1 in 2 ** 250.
221 // One of the following will fail.
222 EXPECT_TRUE(false_event_seen);
223 EXPECT_TRUE(true_event_seen);
224 }
225
TEST_F(FieldTrialTest,OneWinner)226 TEST_F(FieldTrialTest, OneWinner) {
227 char name[] = "Some name";
228 char default_group_name[] = "Default some name";
229 int group_count(10);
230
231 int default_group_number = -1;
232 scoped_refptr<FieldTrial> trial =
233 CreateFieldTrial(name, group_count, default_group_name, NULL);
234 int winner_index(-2);
235 std::string winner_name;
236
237 for (int i = 1; i <= group_count; ++i) {
238 int might_win = trial->AppendGroup(std::string(), 1);
239
240 // Because we keep appending groups, we want to see if the last group that
241 // was added has been assigned or not.
242 if (trial->group_ == might_win) {
243 EXPECT_EQ(-2, winner_index);
244 winner_index = might_win;
245 StringAppendF(&winner_name, "%d", might_win);
246 EXPECT_EQ(winner_name, trial->group_name());
247 }
248 }
249 EXPECT_GE(winner_index, 0);
250 // Since all groups cover the total probability, we should not have
251 // chosen the default group.
252 EXPECT_NE(trial->group(), default_group_number);
253 EXPECT_EQ(trial->group(), winner_index);
254 EXPECT_EQ(trial->group_name(), winner_name);
255 }
256
TEST_F(FieldTrialTest,DisableProbability)257 TEST_F(FieldTrialTest, DisableProbability) {
258 const std::string default_group_name = "Default group";
259 const std::string loser = "Loser";
260 const std::string name = "Trial";
261
262 // Create a field trail that has expired.
263 int default_group_number = -1;
264 FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
265 name, 1000000000, default_group_name, OneYearBeforeBuildTime(), 1, 1,
266 FieldTrial::SESSION_RANDOMIZED,
267 &default_group_number);
268 trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen.
269
270 // Because trial has expired, we should always be in the default group.
271 EXPECT_EQ(default_group_number, trial->group());
272
273 // And that default_group_name should ALWAYS win.
274 EXPECT_EQ(default_group_name, trial->group_name());
275 }
276
TEST_F(FieldTrialTest,ActiveGroups)277 TEST_F(FieldTrialTest, ActiveGroups) {
278 std::string no_group("No Group");
279 scoped_refptr<FieldTrial> trial =
280 CreateFieldTrial(no_group, 10, "Default", NULL);
281
282 // There is no winner yet, so no NameGroupId should be returned.
283 FieldTrial::ActiveGroup active_group;
284 EXPECT_FALSE(trial->GetActiveGroup(&active_group));
285
286 // Create a single winning group.
287 std::string one_winner("One Winner");
288 trial = CreateFieldTrial(one_winner, 10, "Default", NULL);
289 std::string winner("Winner");
290 trial->AppendGroup(winner, 10);
291 EXPECT_FALSE(trial->GetActiveGroup(&active_group));
292 // Finalize the group selection by accessing the selected group.
293 trial->group();
294 EXPECT_TRUE(trial->GetActiveGroup(&active_group));
295 EXPECT_EQ(one_winner, active_group.trial_name);
296 EXPECT_EQ(winner, active_group.group_name);
297
298 std::string multi_group("MultiGroup");
299 scoped_refptr<FieldTrial> multi_group_trial =
300 CreateFieldTrial(multi_group, 9, "Default", NULL);
301
302 multi_group_trial->AppendGroup("Me", 3);
303 multi_group_trial->AppendGroup("You", 3);
304 multi_group_trial->AppendGroup("Them", 3);
305 EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group));
306 // Finalize the group selection by accessing the selected group.
307 multi_group_trial->group();
308 EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
309 EXPECT_EQ(multi_group, active_group.trial_name);
310 EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
311
312 // Now check if the list is built properly...
313 FieldTrial::ActiveGroups active_groups;
314 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
315 EXPECT_EQ(2U, active_groups.size());
316 for (size_t i = 0; i < active_groups.size(); ++i) {
317 // Order is not guaranteed, so check all values.
318 EXPECT_NE(no_group, active_groups[i].trial_name);
319 EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
320 winner == active_groups[i].group_name);
321 EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
322 multi_group_trial->group_name() == active_groups[i].group_name);
323 }
324 }
325
TEST_F(FieldTrialTest,GetActiveFieldTrialGroupsFromString)326 TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) {
327 FieldTrial::ActiveGroups active_groups;
328 FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z",
329 &active_groups);
330 ASSERT_EQ(2U, active_groups.size());
331 EXPECT_EQ("A", active_groups[0].trial_name);
332 EXPECT_EQ("X", active_groups[0].group_name);
333 EXPECT_EQ("C", active_groups[1].trial_name);
334 EXPECT_EQ("Z", active_groups[1].group_name);
335 }
336
TEST_F(FieldTrialTest,AllGroups)337 TEST_F(FieldTrialTest, AllGroups) {
338 FieldTrial::State field_trial_state;
339 std::string one_winner("One Winner");
340 scoped_refptr<FieldTrial> trial =
341 CreateFieldTrial(one_winner, 10, "Default", NULL);
342 std::string winner("Winner");
343 trial->AppendGroup(winner, 10);
344 EXPECT_TRUE(trial->GetState(&field_trial_state));
345 EXPECT_EQ(one_winner, *field_trial_state.trial_name);
346 EXPECT_EQ(winner, *field_trial_state.group_name);
347 trial->group();
348 EXPECT_TRUE(trial->GetState(&field_trial_state));
349 EXPECT_EQ(one_winner, *field_trial_state.trial_name);
350 EXPECT_EQ(winner, *field_trial_state.group_name);
351
352 std::string multi_group("MultiGroup");
353 scoped_refptr<FieldTrial> multi_group_trial =
354 CreateFieldTrial(multi_group, 9, "Default", NULL);
355
356 multi_group_trial->AppendGroup("Me", 3);
357 multi_group_trial->AppendGroup("You", 3);
358 multi_group_trial->AppendGroup("Them", 3);
359 EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
360 // Finalize the group selection by accessing the selected group.
361 multi_group_trial->group();
362 EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
363 EXPECT_EQ(multi_group, *field_trial_state.trial_name);
364 EXPECT_EQ(multi_group_trial->group_name(), *field_trial_state.group_name);
365 }
366
TEST_F(FieldTrialTest,ActiveGroupsNotFinalized)367 TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
368 const char kTrialName[] = "TestTrial";
369 const char kSecondaryGroupName[] = "SecondaryGroup";
370
371 int default_group = -1;
372 scoped_refptr<FieldTrial> trial =
373 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
374 const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
375
376 // Before |group()| is called, |GetActiveGroup()| should return false.
377 FieldTrial::ActiveGroup active_group;
378 EXPECT_FALSE(trial->GetActiveGroup(&active_group));
379
380 // |GetActiveFieldTrialGroups()| should also not include the trial.
381 FieldTrial::ActiveGroups active_groups;
382 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
383 EXPECT_TRUE(active_groups.empty());
384
385 // After |group()| has been called, both APIs should succeed.
386 const int chosen_group = trial->group();
387 EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
388
389 EXPECT_TRUE(trial->GetActiveGroup(&active_group));
390 EXPECT_EQ(kTrialName, active_group.trial_name);
391 if (chosen_group == default_group)
392 EXPECT_EQ(kDefaultGroupName, active_group.group_name);
393 else
394 EXPECT_EQ(kSecondaryGroupName, active_group.group_name);
395
396 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
397 ASSERT_EQ(1U, active_groups.size());
398 EXPECT_EQ(kTrialName, active_groups[0].trial_name);
399 EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
400 }
401
TEST_F(FieldTrialTest,GetGroupNameWithoutActivation)402 TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) {
403 const char kTrialName[] = "TestTrial";
404 const char kSecondaryGroupName[] = "SecondaryGroup";
405
406 int default_group = -1;
407 scoped_refptr<FieldTrial> trial =
408 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
409 trial->AppendGroup(kSecondaryGroupName, 50);
410
411 // The trial should start inactive.
412 EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
413
414 // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
415 std::string group_name = trial->GetGroupNameWithoutActivation();
416 EXPECT_FALSE(group_name.empty());
417 EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
418
419 // Calling |group_name()| should activate it and return the same group name.
420 EXPECT_EQ(group_name, trial->group_name());
421 EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
422 }
423
TEST_F(FieldTrialTest,Save)424 TEST_F(FieldTrialTest, Save) {
425 std::string save_string;
426
427 scoped_refptr<FieldTrial> trial =
428 CreateFieldTrial("Some name", 10, "Default some name", NULL);
429 // There is no winner yet, so no textual group name is associated with trial.
430 // In this case, the trial should not be included.
431 EXPECT_EQ("", trial->group_name_internal());
432 FieldTrialList::StatesToString(&save_string);
433 EXPECT_EQ("", save_string);
434 save_string.clear();
435
436 // Create a winning group.
437 trial->AppendGroup("Winner", 10);
438 // Finalize the group selection by accessing the selected group.
439 trial->group();
440 FieldTrialList::StatesToString(&save_string);
441 EXPECT_EQ("Some name/Winner/", save_string);
442 save_string.clear();
443
444 // Create a second trial and winning group.
445 scoped_refptr<FieldTrial> trial2 =
446 CreateFieldTrial("xxx", 10, "Default xxx", NULL);
447 trial2->AppendGroup("yyyy", 10);
448 // Finalize the group selection by accessing the selected group.
449 trial2->group();
450
451 FieldTrialList::StatesToString(&save_string);
452 // We assume names are alphabetized... though this is not critical.
453 EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string);
454 save_string.clear();
455
456 // Create a third trial with only the default group.
457 scoped_refptr<FieldTrial> trial3 =
458 CreateFieldTrial("zzz", 10, "default", NULL);
459 // Finalize the group selection by accessing the selected group.
460 trial3->group();
461
462 FieldTrialList::StatesToString(&save_string);
463 EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
464 }
465
TEST_F(FieldTrialTest,SaveAll)466 TEST_F(FieldTrialTest, SaveAll) {
467 std::string save_string;
468
469 scoped_refptr<FieldTrial> trial =
470 CreateFieldTrial("Some name", 10, "Default some name", nullptr);
471 EXPECT_EQ("", trial->group_name_internal());
472 FieldTrialList::AllStatesToString(&save_string);
473 EXPECT_EQ("Some name/Default some name/", save_string);
474 // Getting all states should have finalized the trial.
475 EXPECT_EQ("Default some name", trial->group_name_internal());
476 save_string.clear();
477
478 // Create a winning group.
479 trial = CreateFieldTrial("trial2", 10, "Default some name", nullptr);
480 trial->AppendGroup("Winner", 10);
481 // Finalize the group selection by accessing the selected group.
482 trial->group();
483 FieldTrialList::AllStatesToString(&save_string);
484 EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
485 save_string.clear();
486
487 // Create a second trial and winning group.
488 scoped_refptr<FieldTrial> trial2 =
489 CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
490 trial2->AppendGroup("yyyy", 10);
491 // Finalize the group selection by accessing the selected group.
492 trial2->group();
493
494 FieldTrialList::AllStatesToString(&save_string);
495 // We assume names are alphabetized... though this is not critical.
496 EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/",
497 save_string);
498 save_string.clear();
499
500 // Create a third trial with only the default group.
501 scoped_refptr<FieldTrial> trial3 =
502 CreateFieldTrial("zzz", 10, "default", NULL);
503
504 FieldTrialList::AllStatesToString(&save_string);
505 EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
506 save_string);
507 }
508
TEST_F(FieldTrialTest,Restore)509 TEST_F(FieldTrialTest, Restore) {
510 ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
511 ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
512
513 FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/",
514 std::set<std::string>());
515
516 FieldTrial* trial = FieldTrialList::Find("Some_name");
517 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
518 EXPECT_EQ("Winner", trial->group_name());
519 EXPECT_EQ("Some_name", trial->trial_name());
520
521 trial = FieldTrialList::Find("xxx");
522 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
523 EXPECT_EQ("yyyy", trial->group_name());
524 EXPECT_EQ("xxx", trial->trial_name());
525 }
526
TEST_F(FieldTrialTest,RestoreNotEndingWithSlash)527 TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
528 EXPECT_TRUE(FieldTrialList::CreateTrialsFromString("tname/gname",
529 std::set<std::string>()));
530
531 FieldTrial* trial = FieldTrialList::Find("tname");
532 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
533 EXPECT_EQ("gname", trial->group_name());
534 EXPECT_EQ("tname", trial->trial_name());
535 }
536
TEST_F(FieldTrialTest,BogusRestore)537 TEST_F(FieldTrialTest, BogusRestore) {
538 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingSlash",
539 std::set<std::string>()));
540 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/",
541 std::set<std::string>()));
542 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("noname, only group/",
543 std::set<std::string>()));
544 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("/emptyname",
545 std::set<std::string>()));
546 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("*/emptyname",
547 std::set<std::string>()));
548 }
549
TEST_F(FieldTrialTest,DuplicateRestore)550 TEST_F(FieldTrialTest, DuplicateRestore) {
551 scoped_refptr<FieldTrial> trial =
552 CreateFieldTrial("Some name", 10, "Default", NULL);
553 trial->AppendGroup("Winner", 10);
554 // Finalize the group selection by accessing the selected group.
555 trial->group();
556 std::string save_string;
557 FieldTrialList::StatesToString(&save_string);
558 EXPECT_EQ("Some name/Winner/", save_string);
559
560 // It is OK if we redundantly specify a winner.
561 EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(save_string,
562 std::set<std::string>()));
563
564 // But it is an error to try to change to a different winner.
565 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/",
566 std::set<std::string>()));
567 }
568
TEST_F(FieldTrialTest,CreateTrialsFromStringNotActive)569 TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
570 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
571 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
572 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/Xyz/zyx/",
573 std::set<std::string>()));
574
575 FieldTrial::ActiveGroups active_groups;
576 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
577 ASSERT_TRUE(active_groups.empty());
578
579 // Check that the values still get returned and querying them activates them.
580 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
581 EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
582
583 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
584 ASSERT_EQ(2U, active_groups.size());
585 EXPECT_EQ("Abc", active_groups[0].trial_name);
586 EXPECT_EQ("def", active_groups[0].group_name);
587 EXPECT_EQ("Xyz", active_groups[1].trial_name);
588 EXPECT_EQ("zyx", active_groups[1].group_name);
589 }
590
TEST_F(FieldTrialTest,CreateTrialsFromStringForceActivation)591 TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) {
592 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
593 ASSERT_FALSE(FieldTrialList::TrialExists("def"));
594 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
595 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
596 "*Abc/cba/def/fed/*Xyz/zyx/", std::set<std::string>()));
597
598 FieldTrial::ActiveGroups active_groups;
599 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
600 ASSERT_EQ(2U, active_groups.size());
601 EXPECT_EQ("Abc", active_groups[0].trial_name);
602 EXPECT_EQ("cba", active_groups[0].group_name);
603 EXPECT_EQ("Xyz", active_groups[1].trial_name);
604 EXPECT_EQ("zyx", active_groups[1].group_name);
605 }
606
TEST_F(FieldTrialTest,CreateTrialsFromStringNotActiveObserver)607 TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
608 ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
609
610 TestFieldTrialObserver observer;
611 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/",
612 std::set<std::string>()));
613 RunLoop().RunUntilIdle();
614 // Observer shouldn't be notified.
615 EXPECT_TRUE(observer.trial_name().empty());
616
617 // Check that the values still get returned and querying them activates them.
618 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
619
620 RunLoop().RunUntilIdle();
621 EXPECT_EQ("Abc", observer.trial_name());
622 EXPECT_EQ("def", observer.group_name());
623 }
624
TEST_F(FieldTrialTest,CreateTrialsFromStringWithIgnoredFieldTrials)625 TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) {
626 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
627 ASSERT_FALSE(FieldTrialList::TrialExists("Foo"));
628 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
629 ASSERT_FALSE(FieldTrialList::TrialExists("Bar"));
630 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
631
632 std::set<std::string> ignored_trial_names;
633 ignored_trial_names.insert("Unaccepted1");
634 ignored_trial_names.insert("Unaccepted2");
635 ignored_trial_names.insert("Unaccepted3");
636
637 FieldTrialList::CreateTrialsFromString(
638 "Unaccepted1/Unaccepted1_name/"
639 "Foo/Foo_name/"
640 "Unaccepted2/Unaccepted2_name/"
641 "Bar/Bar_name/"
642 "Unaccepted3/Unaccepted3_name/",
643 ignored_trial_names);
644
645 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
646 EXPECT_TRUE(FieldTrialList::TrialExists("Foo"));
647 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
648 EXPECT_TRUE(FieldTrialList::TrialExists("Bar"));
649 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
650
651 FieldTrial::ActiveGroups active_groups;
652 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
653 EXPECT_TRUE(active_groups.empty());
654
655 FieldTrial* trial = FieldTrialList::Find("Foo");
656 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
657 EXPECT_EQ("Foo", trial->trial_name());
658 EXPECT_EQ("Foo_name", trial->group_name());
659
660 trial = FieldTrialList::Find("Bar");
661 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
662 EXPECT_EQ("Bar", trial->trial_name());
663 EXPECT_EQ("Bar_name", trial->group_name());
664 }
665
TEST_F(FieldTrialTest,CreateFieldTrial)666 TEST_F(FieldTrialTest, CreateFieldTrial) {
667 ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
668
669 FieldTrialList::CreateFieldTrial("Some_name", "Winner");
670
671 FieldTrial* trial = FieldTrialList::Find("Some_name");
672 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
673 EXPECT_EQ("Winner", trial->group_name());
674 EXPECT_EQ("Some_name", trial->trial_name());
675 }
676
TEST_F(FieldTrialTest,CreateFieldTrialIsNotActive)677 TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
678 const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
679 const char kWinnerGroup[] = "Winner";
680 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
681 FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
682
683 FieldTrial::ActiveGroups active_groups;
684 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
685 EXPECT_TRUE(active_groups.empty());
686 }
687
TEST_F(FieldTrialTest,DuplicateFieldTrial)688 TEST_F(FieldTrialTest, DuplicateFieldTrial) {
689 scoped_refptr<FieldTrial> trial =
690 CreateFieldTrial("Some_name", 10, "Default", NULL);
691 trial->AppendGroup("Winner", 10);
692
693 // It is OK if we redundantly specify a winner.
694 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
695 EXPECT_TRUE(trial1 != NULL);
696
697 // But it is an error to try to change to a different winner.
698 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
699 EXPECT_TRUE(trial2 == NULL);
700 }
701
TEST_F(FieldTrialTest,DisableImmediately)702 TEST_F(FieldTrialTest, DisableImmediately) {
703 int default_group_number = -1;
704 scoped_refptr<FieldTrial> trial =
705 CreateFieldTrial("trial", 100, "default", &default_group_number);
706 trial->Disable();
707 ASSERT_EQ("default", trial->group_name());
708 ASSERT_EQ(default_group_number, trial->group());
709 }
710
TEST_F(FieldTrialTest,DisableAfterInitialization)711 TEST_F(FieldTrialTest, DisableAfterInitialization) {
712 scoped_refptr<FieldTrial> trial =
713 CreateFieldTrial("trial", 100, "default", NULL);
714 trial->AppendGroup("non_default", 100);
715 trial->Disable();
716 ASSERT_EQ("default", trial->group_name());
717 }
718
TEST_F(FieldTrialTest,ForcedFieldTrials)719 TEST_F(FieldTrialTest, ForcedFieldTrials) {
720 // Validate we keep the forced choice.
721 FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
722 "Force");
723 EXPECT_STREQ("Force", forced_trial->group_name().c_str());
724
725 int default_group_number = -1;
726 scoped_refptr<FieldTrial> factory_trial =
727 CreateFieldTrial("Use the", 1000, "default", &default_group_number);
728 EXPECT_EQ(factory_trial.get(), forced_trial);
729
730 int chosen_group = factory_trial->AppendGroup("Force", 100);
731 EXPECT_EQ(chosen_group, factory_trial->group());
732 int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100);
733 EXPECT_NE(chosen_group, not_chosen_group);
734
735 // Since we didn't force the default group, we should not be returned the
736 // chosen group as the default group.
737 EXPECT_NE(default_group_number, chosen_group);
738 int new_group = factory_trial->AppendGroup("Duck Tape", 800);
739 EXPECT_NE(chosen_group, new_group);
740 // The new group should not be the default group either.
741 EXPECT_NE(default_group_number, new_group);
742 }
743
TEST_F(FieldTrialTest,ForcedFieldTrialsDefaultGroup)744 TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
745 // Forcing the default should use the proper group ID.
746 FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name",
747 "Default");
748 int default_group_number = -1;
749 scoped_refptr<FieldTrial> factory_trial =
750 CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number);
751 EXPECT_EQ(forced_trial, factory_trial.get());
752
753 int other_group = factory_trial->AppendGroup("Not Default", 100);
754 EXPECT_STREQ("Default", factory_trial->group_name().c_str());
755 EXPECT_EQ(default_group_number, factory_trial->group());
756 EXPECT_NE(other_group, factory_trial->group());
757
758 int new_other_group = factory_trial->AppendGroup("Not Default Either", 800);
759 EXPECT_NE(new_other_group, factory_trial->group());
760 }
761
TEST_F(FieldTrialTest,SetForced)762 TEST_F(FieldTrialTest, SetForced) {
763 // Start by setting a trial for which we ensure a winner...
764 int default_group_number = -1;
765 scoped_refptr<FieldTrial> forced_trial =
766 CreateFieldTrial("Use the", 1, "default", &default_group_number);
767 EXPECT_EQ(forced_trial, forced_trial);
768
769 int forced_group = forced_trial->AppendGroup("Force", 1);
770 EXPECT_EQ(forced_group, forced_trial->group());
771
772 // Now force it.
773 forced_trial->SetForced();
774
775 // Now try to set it up differently as a hard coded registration would.
776 scoped_refptr<FieldTrial> hard_coded_trial =
777 CreateFieldTrial("Use the", 1, "default", &default_group_number);
778 EXPECT_EQ(hard_coded_trial, forced_trial);
779
780 int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
781 EXPECT_EQ(forced_group, hard_coded_trial->group());
782 EXPECT_EQ(forced_group, would_lose_group);
783
784 // Same thing if we would have done it to win again.
785 scoped_refptr<FieldTrial> other_hard_coded_trial =
786 CreateFieldTrial("Use the", 1, "default", &default_group_number);
787 EXPECT_EQ(other_hard_coded_trial, forced_trial);
788
789 int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
790 EXPECT_EQ(forced_group, other_hard_coded_trial->group());
791 EXPECT_EQ(forced_group, would_win_group);
792 }
793
TEST_F(FieldTrialTest,SetForcedDefaultOnly)794 TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
795 const char kTrialName[] = "SetForcedDefaultOnly";
796 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
797
798 int default_group = -1;
799 scoped_refptr<FieldTrial> trial =
800 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
801 trial->SetForced();
802
803 trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
804 EXPECT_EQ(default_group, trial->group());
805 EXPECT_EQ(kDefaultGroupName, trial->group_name());
806 }
807
TEST_F(FieldTrialTest,SetForcedDefaultWithExtraGroup)808 TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
809 const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
810 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
811
812 int default_group = -1;
813 scoped_refptr<FieldTrial> trial =
814 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
815 trial->SetForced();
816
817 trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
818 const int extra_group = trial->AppendGroup("Extra", 100);
819 EXPECT_EQ(default_group, trial->group());
820 EXPECT_NE(extra_group, trial->group());
821 EXPECT_EQ(kDefaultGroupName, trial->group_name());
822 }
823
TEST_F(FieldTrialTest,SetForcedTurnFeatureOn)824 TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
825 const char kTrialName[] = "SetForcedTurnFeatureOn";
826 const char kExtraGroupName[] = "Extra";
827 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
828
829 // Simulate a server-side (forced) config that turns the feature on when the
830 // original hard-coded config had it disabled.
831 scoped_refptr<FieldTrial> forced_trial =
832 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
833 forced_trial->AppendGroup(kExtraGroupName, 100);
834 forced_trial->SetForced();
835
836 int default_group = -1;
837 scoped_refptr<FieldTrial> client_trial =
838 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
839 const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0);
840 EXPECT_NE(default_group, extra_group);
841
842 EXPECT_FALSE(client_trial->group_reported_);
843 EXPECT_EQ(extra_group, client_trial->group());
844 EXPECT_TRUE(client_trial->group_reported_);
845 EXPECT_EQ(kExtraGroupName, client_trial->group_name());
846 }
847
TEST_F(FieldTrialTest,SetForcedTurnFeatureOff)848 TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
849 const char kTrialName[] = "SetForcedTurnFeatureOff";
850 const char kExtraGroupName[] = "Extra";
851 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
852
853 // Simulate a server-side (forced) config that turns the feature off when the
854 // original hard-coded config had it enabled.
855 scoped_refptr<FieldTrial> forced_trial =
856 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
857 forced_trial->AppendGroup(kExtraGroupName, 0);
858 forced_trial->SetForced();
859
860 int default_group = -1;
861 scoped_refptr<FieldTrial> client_trial =
862 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
863 const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100);
864 EXPECT_NE(default_group, extra_group);
865
866 EXPECT_FALSE(client_trial->group_reported_);
867 EXPECT_EQ(default_group, client_trial->group());
868 EXPECT_TRUE(client_trial->group_reported_);
869 EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
870 }
871
TEST_F(FieldTrialTest,SetForcedChangeDefault_Default)872 TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
873 const char kTrialName[] = "SetForcedDefaultGroupChange";
874 const char kGroupAName[] = "A";
875 const char kGroupBName[] = "B";
876 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
877
878 // Simulate a server-side (forced) config that switches which group is default
879 // and ensures that the non-forced code receives the correct group numbers.
880 scoped_refptr<FieldTrial> forced_trial =
881 CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
882 forced_trial->AppendGroup(kGroupBName, 100);
883 forced_trial->SetForced();
884
885 int default_group = -1;
886 scoped_refptr<FieldTrial> client_trial =
887 CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
888 const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
889 EXPECT_NE(default_group, extra_group);
890
891 EXPECT_FALSE(client_trial->group_reported_);
892 EXPECT_EQ(default_group, client_trial->group());
893 EXPECT_TRUE(client_trial->group_reported_);
894 EXPECT_EQ(kGroupBName, client_trial->group_name());
895 }
896
TEST_F(FieldTrialTest,SetForcedChangeDefault_NonDefault)897 TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
898 const char kTrialName[] = "SetForcedDefaultGroupChange";
899 const char kGroupAName[] = "A";
900 const char kGroupBName[] = "B";
901 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
902
903 // Simulate a server-side (forced) config that switches which group is default
904 // and ensures that the non-forced code receives the correct group numbers.
905 scoped_refptr<FieldTrial> forced_trial =
906 CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
907 forced_trial->AppendGroup(kGroupBName, 0);
908 forced_trial->SetForced();
909
910 int default_group = -1;
911 scoped_refptr<FieldTrial> client_trial =
912 CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
913 const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
914 EXPECT_NE(default_group, extra_group);
915
916 EXPECT_FALSE(client_trial->group_reported_);
917 EXPECT_EQ(extra_group, client_trial->group());
918 EXPECT_TRUE(client_trial->group_reported_);
919 EXPECT_EQ(kGroupAName, client_trial->group_name());
920 }
921
TEST_F(FieldTrialTest,Observe)922 TEST_F(FieldTrialTest, Observe) {
923 const char kTrialName[] = "TrialToObserve1";
924 const char kSecondaryGroupName[] = "SecondaryGroup";
925
926 TestFieldTrialObserver observer;
927 int default_group = -1;
928 scoped_refptr<FieldTrial> trial =
929 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
930 const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
931 const int chosen_group = trial->group();
932 EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
933
934 RunLoop().RunUntilIdle();
935 EXPECT_EQ(kTrialName, observer.trial_name());
936 if (chosen_group == default_group)
937 EXPECT_EQ(kDefaultGroupName, observer.group_name());
938 else
939 EXPECT_EQ(kSecondaryGroupName, observer.group_name());
940 }
941
TEST_F(FieldTrialTest,ObserveDisabled)942 TEST_F(FieldTrialTest, ObserveDisabled) {
943 const char kTrialName[] = "TrialToObserve2";
944
945 TestFieldTrialObserver observer;
946 int default_group = -1;
947 scoped_refptr<FieldTrial> trial =
948 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
949 trial->AppendGroup("A", 25);
950 trial->AppendGroup("B", 25);
951 trial->AppendGroup("C", 25);
952 trial->Disable();
953
954 // Observer shouldn't be notified of a disabled trial.
955 RunLoop().RunUntilIdle();
956 EXPECT_TRUE(observer.trial_name().empty());
957 EXPECT_TRUE(observer.group_name().empty());
958
959 // Observer shouldn't be notified even after a |group()| call.
960 EXPECT_EQ(default_group, trial->group());
961 RunLoop().RunUntilIdle();
962 EXPECT_TRUE(observer.trial_name().empty());
963 EXPECT_TRUE(observer.group_name().empty());
964 }
965
TEST_F(FieldTrialTest,ObserveForcedDisabled)966 TEST_F(FieldTrialTest, ObserveForcedDisabled) {
967 const char kTrialName[] = "TrialToObserve3";
968
969 TestFieldTrialObserver observer;
970 int default_group = -1;
971 scoped_refptr<FieldTrial> trial =
972 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
973 trial->AppendGroup("A", 25);
974 trial->AppendGroup("B", 25);
975 trial->AppendGroup("C", 25);
976 trial->SetForced();
977 trial->Disable();
978
979 // Observer shouldn't be notified of a disabled trial, even when forced.
980 RunLoop().RunUntilIdle();
981 EXPECT_TRUE(observer.trial_name().empty());
982 EXPECT_TRUE(observer.group_name().empty());
983
984 // Observer shouldn't be notified even after a |group()| call.
985 EXPECT_EQ(default_group, trial->group());
986 RunLoop().RunUntilIdle();
987 EXPECT_TRUE(observer.trial_name().empty());
988 EXPECT_TRUE(observer.group_name().empty());
989 }
990
TEST_F(FieldTrialTest,DisabledTrialNotActive)991 TEST_F(FieldTrialTest, DisabledTrialNotActive) {
992 const char kTrialName[] = "DisabledTrial";
993 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
994
995 scoped_refptr<FieldTrial> trial =
996 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
997 trial->AppendGroup("X", 50);
998 trial->Disable();
999
1000 // Ensure the trial is not listed as active.
1001 FieldTrial::ActiveGroups active_groups;
1002 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
1003 EXPECT_TRUE(active_groups.empty());
1004
1005 // Ensure the trial is not listed in the |StatesToString()| result.
1006 std::string states;
1007 FieldTrialList::StatesToString(&states);
1008 EXPECT_TRUE(states.empty());
1009 }
1010
TEST_F(FieldTrialTest,ExpirationYearNotExpired)1011 TEST_F(FieldTrialTest, ExpirationYearNotExpired) {
1012 const char kTrialName[] = "NotExpired";
1013 const char kGroupName[] = "Group2";
1014 const int kProbability = 100;
1015 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
1016
1017 scoped_refptr<FieldTrial> trial =
1018 CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL);
1019 trial->AppendGroup(kGroupName, kProbability);
1020 EXPECT_EQ(kGroupName, trial->group_name());
1021 }
1022
TEST_F(FieldTrialTest,FloatBoundariesGiveEqualGroupSizes)1023 TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
1024 const int kBucketCount = 100;
1025
1026 // Try each boundary value |i / 100.0| as the entropy value.
1027 for (int i = 0; i < kBucketCount; ++i) {
1028 const double entropy = i / static_cast<double>(kBucketCount);
1029
1030 scoped_refptr<base::FieldTrial> trial(
1031 new base::FieldTrial("test", kBucketCount, "default", entropy));
1032 for (int j = 0; j < kBucketCount; ++j)
1033 trial->AppendGroup(base::IntToString(j), 1);
1034
1035 EXPECT_EQ(base::IntToString(i), trial->group_name());
1036 }
1037 }
1038
TEST_F(FieldTrialTest,DoesNotSurpassTotalProbability)1039 TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
1040 const double kEntropyValue = 1.0 - 1e-9;
1041 ASSERT_LT(kEntropyValue, 1.0);
1042
1043 scoped_refptr<base::FieldTrial> trial(
1044 new base::FieldTrial("test", 2, "default", kEntropyValue));
1045 trial->AppendGroup("1", 1);
1046 trial->AppendGroup("2", 1);
1047
1048 EXPECT_EQ("2", trial->group_name());
1049 }
1050
TEST_F(FieldTrialTest,CreateSimulatedFieldTrial)1051 TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
1052 const char kTrialName[] = "CreateSimulatedFieldTrial";
1053 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
1054
1055 // Different cases to test, e.g. default vs. non default group being chosen.
1056 struct {
1057 double entropy_value;
1058 const char* expected_group;
1059 } test_cases[] = {
1060 { 0.4, "A" },
1061 { 0.85, "B" },
1062 { 0.95, kDefaultGroupName },
1063 };
1064
1065 for (size_t i = 0; i < arraysize(test_cases); ++i) {
1066 TestFieldTrialObserver observer;
1067 scoped_refptr<FieldTrial> trial(
1068 FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName,
1069 test_cases[i].entropy_value));
1070 trial->AppendGroup("A", 80);
1071 trial->AppendGroup("B", 10);
1072 EXPECT_EQ(test_cases[i].expected_group, trial->group_name());
1073
1074 // Field trial shouldn't have been registered with the list.
1075 EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
1076 EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
1077
1078 // Observer shouldn't have been notified.
1079 RunLoop().RunUntilIdle();
1080 EXPECT_TRUE(observer.trial_name().empty());
1081
1082 // The trial shouldn't be in the active set of trials.
1083 FieldTrial::ActiveGroups active_groups;
1084 FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
1085 EXPECT_TRUE(active_groups.empty());
1086
1087 // The trial shouldn't be listed in the |StatesToString()| result.
1088 std::string states;
1089 FieldTrialList::StatesToString(&states);
1090 EXPECT_TRUE(states.empty());
1091 }
1092 }
1093
TEST(FieldTrialTestWithoutList,StatesStringFormat)1094 TEST(FieldTrialTestWithoutList, StatesStringFormat) {
1095 std::string save_string;
1096
1097 // Scoping the first FieldTrialList, as we need another one to test the
1098 // importing function.
1099 {
1100 FieldTrialList field_trial_list(NULL);
1101 scoped_refptr<FieldTrial> trial =
1102 CreateFieldTrial("Abc", 10, "Default some name", NULL);
1103 trial->AppendGroup("cba", 10);
1104 trial->group();
1105 scoped_refptr<FieldTrial> trial2 =
1106 CreateFieldTrial("Xyz", 10, "Default xxx", NULL);
1107 trial2->AppendGroup("zyx", 10);
1108 trial2->group();
1109 scoped_refptr<FieldTrial> trial3 =
1110 CreateFieldTrial("zzz", 10, "default", NULL);
1111
1112 FieldTrialList::AllStatesToString(&save_string);
1113 }
1114
1115 // Starting with a new blank FieldTrialList.
1116 FieldTrialList field_trial_list(NULL);
1117 ASSERT_TRUE(field_trial_list.CreateTrialsFromString(save_string,
1118 std::set<std::string>()));
1119
1120 FieldTrial::ActiveGroups active_groups;
1121 field_trial_list.GetActiveFieldTrialGroups(&active_groups);
1122 ASSERT_EQ(2U, active_groups.size());
1123 EXPECT_EQ("Abc", active_groups[0].trial_name);
1124 EXPECT_EQ("cba", active_groups[0].group_name);
1125 EXPECT_EQ("Xyz", active_groups[1].trial_name);
1126 EXPECT_EQ("zyx", active_groups[1].group_name);
1127 EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
1128 }
1129
TEST(FieldTrialDeathTest,OneTimeRandomizedTrialWithoutFieldTrialList)1130 TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) {
1131 // Trying to instantiate a one-time randomized field trial before the
1132 // FieldTrialList is created should crash.
1133 EXPECT_DEATH_IF_SUPPORTED(
1134 FieldTrialList::FactoryGetFieldTrial(
1135 "OneTimeRandomizedTrialWithoutFieldTrialList", 100, kDefaultGroupName,
1136 base::FieldTrialList::kNoExpirationYear, 1, 1,
1137 base::FieldTrial::ONE_TIME_RANDOMIZED, NULL),
1138 "");
1139 }
1140
1141 #if defined(OS_WIN)
TEST(FieldTrialListTest,TestCopyFieldTrialStateToFlags)1142 TEST(FieldTrialListTest, TestCopyFieldTrialStateToFlags) {
1143 base::FieldTrialList field_trial_list(
1144 base::MakeUnique<base::MockEntropyProvider>());
1145 base::FieldTrialList::CreateFieldTrial("Trial1", "Group1");
1146 base::FilePath test_file_path = base::FilePath(FILE_PATH_LITERAL("Program"));
1147 base::CommandLine cmd_line = base::CommandLine(test_file_path);
1148 const char field_trial_handle[] = "test-field-trial-handle";
1149 const char enable_features_switch[] = "test-enable-features";
1150 const char disable_features_switch[] = "test-disable-features";
1151
1152 base::FieldTrialList::CopyFieldTrialStateToFlags(
1153 field_trial_handle, enable_features_switch, disable_features_switch,
1154 &cmd_line);
1155 EXPECT_TRUE(cmd_line.HasSwitch(field_trial_handle) ||
1156 cmd_line.HasSwitch(switches::kForceFieldTrials));
1157 }
1158 #endif
1159
TEST(FieldTrialListTest,InstantiateAllocator)1160 TEST(FieldTrialListTest, InstantiateAllocator) {
1161 test::ScopedFeatureList scoped_feature_list;
1162 scoped_feature_list.Init();
1163
1164 FieldTrialList field_trial_list(nullptr);
1165 FieldTrialList::CreateFieldTrial("Trial1", "Group1");
1166
1167 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1168 void* memory = field_trial_list.field_trial_allocator_->shared_memory();
1169 size_t used = field_trial_list.field_trial_allocator_->used();
1170
1171 // Ensure that the function is idempotent.
1172 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1173 void* new_memory = field_trial_list.field_trial_allocator_->shared_memory();
1174 size_t new_used = field_trial_list.field_trial_allocator_->used();
1175 EXPECT_EQ(memory, new_memory);
1176 EXPECT_EQ(used, new_used);
1177 }
1178
TEST(FieldTrialListTest,AddTrialsToAllocator)1179 TEST(FieldTrialListTest, AddTrialsToAllocator) {
1180 std::string save_string;
1181 base::SharedMemoryHandle handle;
1182
1183 // Scoping the first FieldTrialList, as we need another one to test that it
1184 // matches.
1185 {
1186 test::ScopedFeatureList scoped_feature_list;
1187 scoped_feature_list.Init();
1188
1189 FieldTrialList field_trial_list(nullptr);
1190 FieldTrialList::CreateFieldTrial("Trial1", "Group1");
1191 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1192 FieldTrialList::AllStatesToString(&save_string);
1193 handle = base::SharedMemory::DuplicateHandle(
1194 field_trial_list.field_trial_allocator_->shared_memory()->handle());
1195 }
1196
1197 FieldTrialList field_trial_list2(nullptr);
1198 std::unique_ptr<base::SharedMemory> shm(new SharedMemory(handle, true));
1199 // 4 KiB is enough to hold the trials only created for this test.
1200 shm.get()->Map(4 << 10);
1201 FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
1202 std::string check_string;
1203 FieldTrialList::AllStatesToString(&check_string);
1204 EXPECT_EQ(save_string, check_string);
1205 }
1206
TEST(FieldTrialListTest,DoNotAddSimulatedFieldTrialsToAllocator)1207 TEST(FieldTrialListTest, DoNotAddSimulatedFieldTrialsToAllocator) {
1208 constexpr char kTrialName[] = "trial";
1209 base::SharedMemoryHandle handle;
1210 {
1211 test::ScopedFeatureList scoped_feature_list;
1212 scoped_feature_list.Init();
1213
1214 // Create a simulated trial and a real trial and call group() on them, which
1215 // should only add the real trial to the field trial allocator.
1216 FieldTrialList field_trial_list(nullptr);
1217 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1218
1219 // This shouldn't add to the allocator.
1220 scoped_refptr<FieldTrial> simulated_trial =
1221 FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, "Simulated",
1222 0.95);
1223 simulated_trial->group();
1224
1225 // This should add to the allocator.
1226 FieldTrial* real_trial =
1227 FieldTrialList::CreateFieldTrial(kTrialName, "Real");
1228 real_trial->group();
1229
1230 handle = base::SharedMemory::DuplicateHandle(
1231 field_trial_list.field_trial_allocator_->shared_memory()->handle());
1232 }
1233
1234 // Check that there's only one entry in the allocator.
1235 FieldTrialList field_trial_list2(nullptr);
1236 std::unique_ptr<base::SharedMemory> shm(new SharedMemory(handle, true));
1237 // 4 KiB is enough to hold the trials only created for this test.
1238 shm.get()->Map(4 << 10);
1239 FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
1240 std::string check_string;
1241 FieldTrialList::AllStatesToString(&check_string);
1242 ASSERT_EQ(check_string.find("Simulated"), std::string::npos);
1243 }
1244
TEST(FieldTrialListTest,AssociateFieldTrialParams)1245 TEST(FieldTrialListTest, AssociateFieldTrialParams) {
1246 test::ScopedFeatureList scoped_feature_list;
1247 scoped_feature_list.Init();
1248
1249 std::string trial_name("Trial1");
1250 std::string group_name("Group1");
1251
1252 // Create a field trial with some params.
1253 FieldTrialList field_trial_list(nullptr);
1254 FieldTrialList::CreateFieldTrial(trial_name, group_name);
1255 std::map<std::string, std::string> params;
1256 params["key1"] = "value1";
1257 params["key2"] = "value2";
1258 FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1259 trial_name, group_name, params);
1260 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1261
1262 // Clear all cached params from the associator.
1263 FieldTrialParamAssociator::GetInstance()->ClearAllCachedParamsForTesting();
1264 // Check that the params have been cleared from the cache.
1265 std::map<std::string, std::string> cached_params;
1266 FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
1267 trial_name, group_name, &cached_params);
1268 EXPECT_EQ(0U, cached_params.size());
1269
1270 // Check that we fetch the param from shared memory properly.
1271 std::map<std::string, std::string> new_params;
1272 FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial_name,
1273 &new_params);
1274 EXPECT_EQ("value1", new_params["key1"]);
1275 EXPECT_EQ("value2", new_params["key2"]);
1276 EXPECT_EQ(2U, new_params.size());
1277 }
1278
TEST(FieldTrialListTest,ClearParamsFromSharedMemory)1279 TEST(FieldTrialListTest, ClearParamsFromSharedMemory) {
1280 std::string trial_name("Trial1");
1281 std::string group_name("Group1");
1282
1283 base::SharedMemoryHandle handle;
1284 {
1285 test::ScopedFeatureList scoped_feature_list;
1286 scoped_feature_list.Init();
1287
1288 // Create a field trial with some params.
1289 FieldTrialList field_trial_list(nullptr);
1290 FieldTrial* trial =
1291 FieldTrialList::CreateFieldTrial(trial_name, group_name);
1292 std::map<std::string, std::string> params;
1293 params["key1"] = "value1";
1294 params["key2"] = "value2";
1295 FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1296 trial_name, group_name, params);
1297 FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
1298
1299 // Clear all params from the associator AND shared memory. The allocated
1300 // segments should be different.
1301 FieldTrial::FieldTrialRef old_ref = trial->ref_;
1302 FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
1303 FieldTrial::FieldTrialRef new_ref = trial->ref_;
1304 EXPECT_NE(old_ref, new_ref);
1305
1306 // Check that there are no params associated with the field trial anymore.
1307 std::map<std::string, std::string> new_params;
1308 FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial_name,
1309 &new_params);
1310 EXPECT_EQ(0U, new_params.size());
1311
1312 // Now duplicate the handle so we can easily check that the trial is still
1313 // in shared memory via AllStatesToString.
1314 handle = base::SharedMemory::DuplicateHandle(
1315 field_trial_list.field_trial_allocator_->shared_memory()->handle());
1316 }
1317
1318 // Check that we have the trial.
1319 FieldTrialList field_trial_list2(nullptr);
1320 std::unique_ptr<base::SharedMemory> shm(new SharedMemory(handle, true));
1321 // 4 KiB is enough to hold the trials only created for this test.
1322 shm.get()->Map(4 << 10);
1323 FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
1324 std::string check_string;
1325 FieldTrialList::AllStatesToString(&check_string);
1326 EXPECT_EQ("*Trial1/Group1/", check_string);
1327 }
1328
TEST(FieldTrialListTest,DumpAndFetchFromSharedMemory)1329 TEST(FieldTrialListTest, DumpAndFetchFromSharedMemory) {
1330 std::string trial_name("Trial1");
1331 std::string group_name("Group1");
1332
1333 // Create a field trial with some params.
1334 FieldTrialList field_trial_list(nullptr);
1335 FieldTrialList::CreateFieldTrial(trial_name, group_name);
1336 std::map<std::string, std::string> params;
1337 params["key1"] = "value1";
1338 params["key2"] = "value2";
1339 FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
1340 trial_name, group_name, params);
1341
1342 std::unique_ptr<base::SharedMemory> shm(new SharedMemory());
1343 // 4 KiB is enough to hold the trials only created for this test.
1344 shm.get()->CreateAndMapAnonymous(4 << 10);
1345 // We _could_ use PersistentMemoryAllocator, this just has less params.
1346 SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false);
1347
1348 // Dump and subsequently retrieve the field trial to |allocator|.
1349 FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(&allocator);
1350 std::vector<const FieldTrial::FieldTrialEntry*> entries =
1351 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(allocator);
1352
1353 // Check that we have the entry we put in.
1354 EXPECT_EQ(1u, entries.size());
1355 const FieldTrial::FieldTrialEntry* entry = entries[0];
1356
1357 // Check that the trial and group names match.
1358 StringPiece shm_trial_name;
1359 StringPiece shm_group_name;
1360 entry->GetTrialAndGroupName(&shm_trial_name, &shm_group_name);
1361 EXPECT_EQ(trial_name, shm_trial_name);
1362 EXPECT_EQ(group_name, shm_group_name);
1363
1364 // Check that the params match.
1365 std::map<std::string, std::string> shm_params;
1366 entry->GetParams(&shm_params);
1367 EXPECT_EQ(2u, shm_params.size());
1368 EXPECT_EQ("value1", shm_params["key1"]);
1369 EXPECT_EQ("value2", shm_params["key2"]);
1370 }
1371
1372 } // namespace base
1373