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