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