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