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