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 14namespace base { 15 16namespace { 17 18// Default group name used by several tests. 19const char kDefaultGroupName[] = "DefaultGroup"; 20 21// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date. 22scoped_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 33int 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. 41class 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 69class 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). 80TEST_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 108TEST_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 136TEST_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 157TEST_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 184TEST_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 209TEST_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 240TEST_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 260TEST_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 308TEST_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 343TEST_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 383TEST_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 std::set<std::string>()); 390 391 FieldTrial* trial = FieldTrialList::Find("Some_name"); 392 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 393 EXPECT_EQ("Winner", trial->group_name()); 394 EXPECT_EQ("Some_name", trial->trial_name()); 395 396 trial = FieldTrialList::Find("xxx"); 397 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 398 EXPECT_EQ("yyyy", trial->group_name()); 399 EXPECT_EQ("xxx", trial->trial_name()); 400} 401 402TEST_F(FieldTrialTest, BogusRestore) { 403 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( 404 "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS, 405 std::set<std::string>())); 406 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( 407 "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS, 408 std::set<std::string>())); 409 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( 410 "MissingFinalSlash/gname", FieldTrialList::DONT_ACTIVATE_TRIALS, 411 std::set<std::string>())); 412 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( 413 "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS, 414 std::set<std::string>())); 415} 416 417TEST_F(FieldTrialTest, DuplicateRestore) { 418 FieldTrial* trial = CreateFieldTrial("Some name", 10, "Default", NULL); 419 trial->AppendGroup("Winner", 10); 420 // Finalize the group selection by accessing the selected group. 421 trial->group(); 422 std::string save_string; 423 FieldTrialList::StatesToString(&save_string); 424 EXPECT_EQ("Some name/Winner/", save_string); 425 426 // It is OK if we redundantly specify a winner. 427 EXPECT_TRUE(FieldTrialList::CreateTrialsFromString( 428 save_string, FieldTrialList::DONT_ACTIVATE_TRIALS, 429 std::set<std::string>())); 430 431 // But it is an error to try to change to a different winner. 432 EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( 433 "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS, 434 std::set<std::string>())); 435} 436 437TEST_F(FieldTrialTest, CreateTrialsFromStringActive) { 438 ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); 439 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); 440 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( 441 "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS, 442 std::set<std::string>())); 443 444 FieldTrial::ActiveGroups active_groups; 445 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 446 ASSERT_EQ(2U, active_groups.size()); 447 EXPECT_EQ("Abc", active_groups[0].trial_name); 448 EXPECT_EQ("def", active_groups[0].group_name); 449 EXPECT_EQ("Xyz", active_groups[1].trial_name); 450 EXPECT_EQ("zyx", active_groups[1].group_name); 451} 452 453TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) { 454 ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); 455 ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); 456 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( 457 "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS, 458 std::set<std::string>())); 459 460 FieldTrial::ActiveGroups active_groups; 461 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 462 ASSERT_TRUE(active_groups.empty()); 463 464 // Check that the values still get returned and querying them activates them. 465 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); 466 EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz")); 467 468 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 469 ASSERT_EQ(2U, active_groups.size()); 470 EXPECT_EQ("Abc", active_groups[0].trial_name); 471 EXPECT_EQ("def", active_groups[0].group_name); 472 EXPECT_EQ("Xyz", active_groups[1].trial_name); 473 EXPECT_EQ("zyx", active_groups[1].group_name); 474} 475 476TEST_F(FieldTrialTest, CreateTrialsFromStringActiveObserver) { 477 ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); 478 479 TestFieldTrialObserver observer; 480 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( 481 "Abc/def/", FieldTrialList::ACTIVATE_TRIALS, std::set<std::string>())); 482 483 RunLoop().RunUntilIdle(); 484 EXPECT_EQ("Abc", observer.trial_name()); 485 EXPECT_EQ("def", observer.group_name()); 486} 487 488TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) { 489 ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); 490 491 TestFieldTrialObserver observer; 492 ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( 493 "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS, 494 std::set<std::string>())); 495 RunLoop().RunUntilIdle(); 496 // Observer shouldn't be notified. 497 EXPECT_TRUE(observer.trial_name().empty()); 498 499 // Check that the values still get returned and querying them activates them. 500 EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); 501 502 RunLoop().RunUntilIdle(); 503 EXPECT_EQ("Abc", observer.trial_name()); 504 EXPECT_EQ("def", observer.group_name()); 505} 506 507TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) { 508 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1")); 509 ASSERT_FALSE(FieldTrialList::TrialExists("Foo")); 510 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2")); 511 ASSERT_FALSE(FieldTrialList::TrialExists("Bar")); 512 ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3")); 513 514 std::set<std::string> ignored_trial_names; 515 ignored_trial_names.insert("Unaccepted1"); 516 ignored_trial_names.insert("Unaccepted2"); 517 ignored_trial_names.insert("Unaccepted3"); 518 519 FieldTrialList::CreateTrialsFromString( 520 "Unaccepted1/Unaccepted1_name/" 521 "Foo/Foo_name/" 522 "Unaccepted2/Unaccepted2_name/" 523 "Bar/Bar_name/" 524 "Unaccepted3/Unaccepted3_name/", 525 FieldTrialList::DONT_ACTIVATE_TRIALS, 526 ignored_trial_names); 527 528 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1")); 529 EXPECT_TRUE(FieldTrialList::TrialExists("Foo")); 530 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2")); 531 EXPECT_TRUE(FieldTrialList::TrialExists("Bar")); 532 EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3")); 533 534 FieldTrial::ActiveGroups active_groups; 535 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 536 EXPECT_TRUE(active_groups.empty()); 537 538 FieldTrial* trial = FieldTrialList::Find("Foo"); 539 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 540 EXPECT_EQ("Foo", trial->trial_name()); 541 EXPECT_EQ("Foo_name", trial->group_name()); 542 543 trial = FieldTrialList::Find("Bar"); 544 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 545 EXPECT_EQ("Bar", trial->trial_name()); 546 EXPECT_EQ("Bar_name", trial->group_name()); 547} 548 549TEST_F(FieldTrialTest, CreateFieldTrial) { 550 ASSERT_FALSE(FieldTrialList::TrialExists("Some_name")); 551 552 FieldTrialList::CreateFieldTrial("Some_name", "Winner"); 553 554 FieldTrial* trial = FieldTrialList::Find("Some_name"); 555 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 556 EXPECT_EQ("Winner", trial->group_name()); 557 EXPECT_EQ("Some_name", trial->trial_name()); 558} 559 560TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) { 561 const char kTrialName[] = "CreateFieldTrialIsActiveTrial"; 562 const char kWinnerGroup[] = "Winner"; 563 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 564 FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup); 565 566 FieldTrial::ActiveGroups active_groups; 567 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 568 EXPECT_TRUE(active_groups.empty()); 569} 570 571TEST_F(FieldTrialTest, DuplicateFieldTrial) { 572 FieldTrial* trial = CreateFieldTrial("Some_name", 10, "Default", NULL); 573 trial->AppendGroup("Winner", 10); 574 575 // It is OK if we redundantly specify a winner. 576 FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner"); 577 EXPECT_TRUE(trial1 != NULL); 578 579 // But it is an error to try to change to a different winner. 580 FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser"); 581 EXPECT_TRUE(trial2 == NULL); 582} 583 584TEST_F(FieldTrialTest, DisableImmediately) { 585 int default_group_number = -1; 586 FieldTrial* trial = 587 CreateFieldTrial("trial", 100, "default", &default_group_number); 588 trial->Disable(); 589 ASSERT_EQ("default", trial->group_name()); 590 ASSERT_EQ(default_group_number, trial->group()); 591} 592 593TEST_F(FieldTrialTest, DisableAfterInitialization) { 594 FieldTrial* trial = CreateFieldTrial("trial", 100, "default", NULL); 595 trial->AppendGroup("non_default", 100); 596 trial->Disable(); 597 ASSERT_EQ("default", trial->group_name()); 598} 599 600TEST_F(FieldTrialTest, ForcedFieldTrials) { 601 // Validate we keep the forced choice. 602 FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the", 603 "Force"); 604 EXPECT_STREQ("Force", forced_trial->group_name().c_str()); 605 606 int default_group_number = -1; 607 FieldTrial* factory_trial = 608 CreateFieldTrial("Use the", 1000, "default", &default_group_number); 609 EXPECT_EQ(factory_trial, forced_trial); 610 611 int chosen_group = factory_trial->AppendGroup("Force", 100); 612 EXPECT_EQ(chosen_group, factory_trial->group()); 613 int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100); 614 EXPECT_NE(chosen_group, not_chosen_group); 615 616 // Since we didn't force the default group, we should not be returned the 617 // chosen group as the default group. 618 EXPECT_NE(default_group_number, chosen_group); 619 int new_group = factory_trial->AppendGroup("Duck Tape", 800); 620 EXPECT_NE(chosen_group, new_group); 621 // The new group should not be the default group either. 622 EXPECT_NE(default_group_number, new_group); 623} 624 625TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) { 626 // Forcing the default should use the proper group ID. 627 FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name", 628 "Default"); 629 int default_group_number = -1; 630 FieldTrial* factory_trial = 631 CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number); 632 EXPECT_EQ(forced_trial, factory_trial); 633 634 int other_group = factory_trial->AppendGroup("Not Default", 100); 635 EXPECT_STREQ("Default", factory_trial->group_name().c_str()); 636 EXPECT_EQ(default_group_number, factory_trial->group()); 637 EXPECT_NE(other_group, factory_trial->group()); 638 639 int new_other_group = factory_trial->AppendGroup("Not Default Either", 800); 640 EXPECT_NE(new_other_group, factory_trial->group()); 641} 642 643TEST_F(FieldTrialTest, SetForced) { 644 // Start by setting a trial for which we ensure a winner... 645 int default_group_number = -1; 646 FieldTrial* forced_trial = 647 CreateFieldTrial("Use the", 1, "default", &default_group_number); 648 EXPECT_EQ(forced_trial, forced_trial); 649 650 int forced_group = forced_trial->AppendGroup("Force", 1); 651 EXPECT_EQ(forced_group, forced_trial->group()); 652 653 // Now force it. 654 forced_trial->SetForced(); 655 656 // Now try to set it up differently as a hard coded registration would. 657 FieldTrial* hard_coded_trial = 658 CreateFieldTrial("Use the", 1, "default", &default_group_number); 659 EXPECT_EQ(hard_coded_trial, forced_trial); 660 661 int would_lose_group = hard_coded_trial->AppendGroup("Force", 0); 662 EXPECT_EQ(forced_group, hard_coded_trial->group()); 663 EXPECT_EQ(forced_group, would_lose_group); 664 665 // Same thing if we would have done it to win again. 666 FieldTrial* other_hard_coded_trial = 667 CreateFieldTrial("Use the", 1, "default", &default_group_number); 668 EXPECT_EQ(other_hard_coded_trial, forced_trial); 669 670 int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1); 671 EXPECT_EQ(forced_group, other_hard_coded_trial->group()); 672 EXPECT_EQ(forced_group, would_win_group); 673} 674 675TEST_F(FieldTrialTest, SetForcedDefaultOnly) { 676 const char kTrialName[] = "SetForcedDefaultOnly"; 677 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 678 679 int default_group = -1; 680 FieldTrial* trial = 681 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 682 trial->SetForced(); 683 684 trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); 685 EXPECT_EQ(default_group, trial->group()); 686 EXPECT_EQ(kDefaultGroupName, trial->group_name()); 687} 688 689TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) { 690 const char kTrialName[] = "SetForcedDefaultWithExtraGroup"; 691 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 692 693 int default_group = -1; 694 FieldTrial* trial = 695 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 696 trial->SetForced(); 697 698 trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); 699 const int extra_group = trial->AppendGroup("Extra", 100); 700 EXPECT_EQ(default_group, trial->group()); 701 EXPECT_NE(extra_group, trial->group()); 702 EXPECT_EQ(kDefaultGroupName, trial->group_name()); 703} 704 705TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) { 706 const char kTrialName[] = "SetForcedTurnFeatureOn"; 707 const char kExtraGroupName[] = "Extra"; 708 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 709 710 // Simulate a server-side (forced) config that turns the feature on when the 711 // original hard-coded config had it disabled. 712 FieldTrial* forced_trial = 713 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); 714 forced_trial->AppendGroup(kExtraGroupName, 100); 715 forced_trial->SetForced(); 716 717 int default_group = -1; 718 FieldTrial* client_trial = 719 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 720 const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0); 721 EXPECT_NE(default_group, extra_group); 722 723 EXPECT_FALSE(client_trial->group_reported_); 724 EXPECT_EQ(extra_group, client_trial->group()); 725 EXPECT_TRUE(client_trial->group_reported_); 726 EXPECT_EQ(kExtraGroupName, client_trial->group_name()); 727} 728 729TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) { 730 const char kTrialName[] = "SetForcedTurnFeatureOff"; 731 const char kExtraGroupName[] = "Extra"; 732 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 733 734 // Simulate a server-side (forced) config that turns the feature off when the 735 // original hard-coded config had it enabled. 736 FieldTrial* forced_trial = 737 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); 738 forced_trial->AppendGroup(kExtraGroupName, 0); 739 forced_trial->SetForced(); 740 741 int default_group = -1; 742 FieldTrial* client_trial = 743 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 744 const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100); 745 EXPECT_NE(default_group, extra_group); 746 747 EXPECT_FALSE(client_trial->group_reported_); 748 EXPECT_EQ(default_group, client_trial->group()); 749 EXPECT_TRUE(client_trial->group_reported_); 750 EXPECT_EQ(kDefaultGroupName, client_trial->group_name()); 751} 752 753TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) { 754 const char kTrialName[] = "SetForcedDefaultGroupChange"; 755 const char kGroupAName[] = "A"; 756 const char kGroupBName[] = "B"; 757 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 758 759 // Simulate a server-side (forced) config that switches which group is default 760 // and ensures that the non-forced code receives the correct group numbers. 761 FieldTrial* forced_trial = 762 CreateFieldTrial(kTrialName, 100, kGroupAName, NULL); 763 forced_trial->AppendGroup(kGroupBName, 100); 764 forced_trial->SetForced(); 765 766 int default_group = -1; 767 FieldTrial* client_trial = 768 CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); 769 const int extra_group = client_trial->AppendGroup(kGroupAName, 50); 770 EXPECT_NE(default_group, extra_group); 771 772 EXPECT_FALSE(client_trial->group_reported_); 773 EXPECT_EQ(default_group, client_trial->group()); 774 EXPECT_TRUE(client_trial->group_reported_); 775 EXPECT_EQ(kGroupBName, client_trial->group_name()); 776} 777 778TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) { 779 const char kTrialName[] = "SetForcedDefaultGroupChange"; 780 const char kGroupAName[] = "A"; 781 const char kGroupBName[] = "B"; 782 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 783 784 // Simulate a server-side (forced) config that switches which group is default 785 // and ensures that the non-forced code receives the correct group numbers. 786 FieldTrial* forced_trial = 787 CreateFieldTrial(kTrialName, 100, kGroupAName, NULL); 788 forced_trial->AppendGroup(kGroupBName, 0); 789 forced_trial->SetForced(); 790 791 int default_group = -1; 792 FieldTrial* client_trial = 793 CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); 794 const int extra_group = client_trial->AppendGroup(kGroupAName, 50); 795 EXPECT_NE(default_group, extra_group); 796 797 EXPECT_FALSE(client_trial->group_reported_); 798 EXPECT_EQ(extra_group, client_trial->group()); 799 EXPECT_TRUE(client_trial->group_reported_); 800 EXPECT_EQ(kGroupAName, client_trial->group_name()); 801} 802 803TEST_F(FieldTrialTest, Observe) { 804 const char kTrialName[] = "TrialToObserve1"; 805 const char kSecondaryGroupName[] = "SecondaryGroup"; 806 807 TestFieldTrialObserver observer; 808 int default_group = -1; 809 FieldTrial* trial = 810 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 811 const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); 812 const int chosen_group = trial->group(); 813 EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); 814 815 RunLoop().RunUntilIdle(); 816 EXPECT_EQ(kTrialName, observer.trial_name()); 817 if (chosen_group == default_group) 818 EXPECT_EQ(kDefaultGroupName, observer.group_name()); 819 else 820 EXPECT_EQ(kSecondaryGroupName, observer.group_name()); 821} 822 823TEST_F(FieldTrialTest, ObserveDisabled) { 824 const char kTrialName[] = "TrialToObserve2"; 825 826 TestFieldTrialObserver observer; 827 int default_group = -1; 828 FieldTrial* trial = 829 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 830 trial->AppendGroup("A", 25); 831 trial->AppendGroup("B", 25); 832 trial->AppendGroup("C", 25); 833 trial->Disable(); 834 835 // Observer shouldn't be notified of a disabled trial. 836 RunLoop().RunUntilIdle(); 837 EXPECT_TRUE(observer.trial_name().empty()); 838 EXPECT_TRUE(observer.group_name().empty()); 839 840 // Observer shouldn't be notified even after a |group()| call. 841 EXPECT_EQ(default_group, trial->group()); 842 RunLoop().RunUntilIdle(); 843 EXPECT_TRUE(observer.trial_name().empty()); 844 EXPECT_TRUE(observer.group_name().empty()); 845} 846 847TEST_F(FieldTrialTest, ObserveForcedDisabled) { 848 const char kTrialName[] = "TrialToObserve3"; 849 850 TestFieldTrialObserver observer; 851 int default_group = -1; 852 FieldTrial* trial = 853 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); 854 trial->AppendGroup("A", 25); 855 trial->AppendGroup("B", 25); 856 trial->AppendGroup("C", 25); 857 trial->SetForced(); 858 trial->Disable(); 859 860 // Observer shouldn't be notified of a disabled trial, even when forced. 861 RunLoop().RunUntilIdle(); 862 EXPECT_TRUE(observer.trial_name().empty()); 863 EXPECT_TRUE(observer.group_name().empty()); 864 865 // Observer shouldn't be notified even after a |group()| call. 866 EXPECT_EQ(default_group, trial->group()); 867 RunLoop().RunUntilIdle(); 868 EXPECT_TRUE(observer.trial_name().empty()); 869 EXPECT_TRUE(observer.group_name().empty()); 870} 871 872TEST_F(FieldTrialTest, DisabledTrialNotActive) { 873 const char kTrialName[] = "DisabledTrial"; 874 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 875 876 FieldTrial* trial = 877 CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); 878 trial->AppendGroup("X", 50); 879 trial->Disable(); 880 881 // Ensure the trial is not listed as active. 882 FieldTrial::ActiveGroups active_groups; 883 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 884 EXPECT_TRUE(active_groups.empty()); 885 886 // Ensure the trial is not listed in the |StatesToString()| result. 887 std::string states; 888 FieldTrialList::StatesToString(&states); 889 EXPECT_TRUE(states.empty()); 890} 891 892TEST_F(FieldTrialTest, ExpirationYearNotExpired) { 893 const char kTrialName[] = "NotExpired"; 894 const char kGroupName[] = "Group2"; 895 const int kProbability = 100; 896 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 897 898 FieldTrial* trial = 899 CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL); 900 trial->AppendGroup(kGroupName, kProbability); 901 EXPECT_EQ(kGroupName, trial->group_name()); 902} 903 904TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) { 905 const int kBucketCount = 100; 906 907 // Try each boundary value |i / 100.0| as the entropy value. 908 for (int i = 0; i < kBucketCount; ++i) { 909 const double entropy = i / static_cast<double>(kBucketCount); 910 911 scoped_refptr<base::FieldTrial> trial( 912 new base::FieldTrial("test", kBucketCount, "default", entropy)); 913 for (int j = 0; j < kBucketCount; ++j) 914 trial->AppendGroup(base::StringPrintf("%d", j), 1); 915 916 EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name()); 917 } 918} 919 920TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) { 921 const double kEntropyValue = 1.0 - 1e-9; 922 ASSERT_LT(kEntropyValue, 1.0); 923 924 scoped_refptr<base::FieldTrial> trial( 925 new base::FieldTrial("test", 2, "default", kEntropyValue)); 926 trial->AppendGroup("1", 1); 927 trial->AppendGroup("2", 1); 928 929 EXPECT_EQ("2", trial->group_name()); 930} 931 932TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) { 933 const char kTrialName[] = "CreateSimulatedFieldTrial"; 934 ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); 935 936 // Different cases to test, e.g. default vs. non default group being chosen. 937 struct { 938 double entropy_value; 939 const char* expected_group; 940 } test_cases[] = { 941 { 0.4, "A" }, 942 { 0.85, "B" }, 943 { 0.95, kDefaultGroupName }, 944 }; 945 946 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 947 TestFieldTrialObserver observer; 948 scoped_refptr<FieldTrial> trial( 949 FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName, 950 test_cases[i].entropy_value)); 951 trial->AppendGroup("A", 80); 952 trial->AppendGroup("B", 10); 953 EXPECT_EQ(test_cases[i].expected_group, trial->group_name()); 954 955 // Field trial shouldn't have been registered with the list. 956 EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName)); 957 EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount()); 958 959 // Observer shouldn't have been notified. 960 RunLoop().RunUntilIdle(); 961 EXPECT_TRUE(observer.trial_name().empty()); 962 963 // The trial shouldn't be in the active set of trials. 964 FieldTrial::ActiveGroups active_groups; 965 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 966 EXPECT_TRUE(active_groups.empty()); 967 968 // The trial shouldn't be listed in the |StatesToString()| result. 969 std::string states; 970 FieldTrialList::StatesToString(&states); 971 EXPECT_TRUE(states.empty()); 972 } 973} 974 975} // namespace base 976