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