field_trial_unittest.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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// Test of FieldTrial class 6 7#include "base/metrics/field_trial.h" 8 9#include "base/stringprintf.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12namespace base { 13 14class FieldTrialTest : public testing::Test { 15 public: 16 FieldTrialTest() : trial_list_() { } 17 18 private: 19 FieldTrialList trial_list_; 20}; 21 22// Test registration, and also check that destructors are called for trials 23// (and that Purify doesn't catch us leaking). 24TEST_F(FieldTrialTest, Registration) { 25 const char* name1 = "name 1 test"; 26 const char* name2 = "name 2 test"; 27 EXPECT_FALSE(FieldTrialList::Find(name1)); 28 EXPECT_FALSE(FieldTrialList::Find(name2)); 29 30 FieldTrial* trial1 = new FieldTrial(name1, 10); 31 EXPECT_EQ(FieldTrial::kNotParticipating, trial1->group()); 32 EXPECT_EQ(name1, trial1->name()); 33 EXPECT_EQ("", trial1->group_name()); 34 35 trial1->AppendGroup("", 7); 36 37 EXPECT_EQ(trial1, FieldTrialList::Find(name1)); 38 EXPECT_FALSE(FieldTrialList::Find(name2)); 39 40 FieldTrial* trial2 = new FieldTrial(name2, 10); 41 EXPECT_EQ(FieldTrial::kNotParticipating, trial2->group()); 42 EXPECT_EQ(name2, trial2->name()); 43 EXPECT_EQ("", trial2->group_name()); 44 45 trial2->AppendGroup("a first group", 7); 46 47 EXPECT_EQ(trial1, FieldTrialList::Find(name1)); 48 EXPECT_EQ(trial2, FieldTrialList::Find(name2)); 49 // Note: FieldTrialList should delete the objects at shutdown. 50} 51 52TEST_F(FieldTrialTest, AbsoluteProbabilities) { 53 char always_true[] = " always true"; 54 char always_false[] = " always false"; 55 for (int i = 1; i < 250; ++i) { 56 // Try lots of names, by changing the first character of the name. 57 always_true[0] = i; 58 always_false[0] = i; 59 60 FieldTrial* trial_true = new FieldTrial(always_true, 10); 61 const std::string winner = "TheWinner"; 62 int winner_group = trial_true->AppendGroup(winner, 10); 63 64 EXPECT_EQ(winner_group, trial_true->group()); 65 EXPECT_EQ(winner, trial_true->group_name()); 66 67 FieldTrial* trial_false = new FieldTrial(always_false, 10); 68 int loser_group = trial_false->AppendGroup("ALoser", 0); 69 70 EXPECT_NE(loser_group, trial_false->group()); 71 } 72} 73 74TEST_F(FieldTrialTest, RemainingProbability) { 75 // First create a test that hasn't had a winner yet. 76 const std::string winner = "Winner"; 77 const std::string loser = "Loser"; 78 scoped_refptr<FieldTrial> trial; 79 int counter = 0; 80 do { 81 std::string name = StringPrintf("trial%d", ++counter); 82 trial = new FieldTrial(name, 10); 83 trial->AppendGroup(loser, 5); // 50% chance of not being chosen. 84 } while (trial->group() != FieldTrial::kNotParticipating); 85 86 // Now add a winner with all remaining probability. 87 trial->AppendGroup(winner, FieldTrial::kAllRemainingProbability); 88 89 // And that winner should ALWAYS win. 90 EXPECT_EQ(winner, trial->group_name()); 91} 92 93TEST_F(FieldTrialTest, FiftyFiftyProbability) { 94 // Check that even with small divisors, we have the proper probabilities, and 95 // all outcomes are possible. Since this is a 50-50 test, it should get both 96 // outcomes in a few tries, but we'll try no more than 100 times (and be flaky 97 // with probability around 1 in 2^99). 98 bool first_winner = false; 99 bool second_winner = false; 100 int counter = 0; 101 do { 102 std::string name = base::StringPrintf("FiftyFifty%d", ++counter); 103 scoped_refptr<FieldTrial> trial = new FieldTrial(name, 2); 104 trial->AppendGroup("first", 1); // 50% chance of being chosen. 105 if (trial->group() != FieldTrial::kNotParticipating) { 106 first_winner = true; 107 continue; 108 } 109 trial->AppendGroup("second", 1); // Always chosen at this point. 110 EXPECT_NE(FieldTrial::kNotParticipating, trial->group()); 111 second_winner = true; 112 } while ((!second_winner || !first_winner) && counter < 100); 113 EXPECT_TRUE(second_winner); 114 EXPECT_TRUE(first_winner); 115} 116 117TEST_F(FieldTrialTest, MiddleProbabilities) { 118 char name[] = " same name"; 119 bool false_event_seen = false; 120 bool true_event_seen = false; 121 for (int i = 1; i < 250; ++i) { 122 name[0] = i; 123 FieldTrial* trial = new FieldTrial(name, 10); 124 int might_win = trial->AppendGroup("MightWin", 5); 125 126 if (trial->group() == might_win) { 127 true_event_seen = true; 128 } else { 129 false_event_seen = true; 130 } 131 if (false_event_seen && true_event_seen) 132 return; // Successful test!!! 133 } 134 // Very surprising to get here. Probability should be around 1 in 2 ** 250. 135 // One of the following will fail. 136 EXPECT_TRUE(false_event_seen); 137 EXPECT_TRUE(true_event_seen); 138} 139 140TEST_F(FieldTrialTest, OneWinner) { 141 char name[] = "Some name"; 142 int group_count(10); 143 144 FieldTrial* trial = new FieldTrial(name, group_count); 145 int winner_index(-2); 146 std::string winner_name; 147 148 for (int i = 1; i <= group_count; ++i) { 149 int might_win = trial->AppendGroup("", 1); 150 151 if (trial->group() == might_win) { 152 EXPECT_EQ(-2, winner_index); 153 winner_index = might_win; 154 StringAppendF(&winner_name, "%d", might_win); 155 EXPECT_EQ(winner_name, trial->group_name()); 156 } 157 } 158 EXPECT_GE(winner_index, 0); 159 EXPECT_EQ(trial->group(), winner_index); 160 EXPECT_EQ(trial->group_name(), winner_name); 161} 162 163TEST_F(FieldTrialTest, Save) { 164 std::string save_string; 165 166 FieldTrial* trial = new FieldTrial("Some name", 10); 167 // There is no winner yet, so no textual group name is associated with trial. 168 EXPECT_EQ("", trial->group_name()); 169 FieldTrialList::StatesToString(&save_string); 170 EXPECT_EQ("", save_string); 171 save_string.clear(); 172 173 // Create a winning group. 174 trial->AppendGroup("Winner", 10); 175 FieldTrialList::StatesToString(&save_string); 176 EXPECT_EQ("Some name/Winner/", save_string); 177 save_string.clear(); 178 179 // Create a second trial and winning group. 180 FieldTrial* trial2 = new FieldTrial("xxx", 10); 181 trial2->AppendGroup("yyyy", 10); 182 183 FieldTrialList::StatesToString(&save_string); 184 // We assume names are alphabetized... though this is not critical. 185 EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string); 186} 187 188TEST_F(FieldTrialTest, Restore) { 189 EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL); 190 EXPECT_TRUE(FieldTrialList::Find("xxx") == NULL); 191 192 FieldTrialList::StringAugmentsState("Some_name/Winner/xxx/yyyy/"); 193 194 FieldTrial* trial = FieldTrialList::Find("Some_name"); 195 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 196 EXPECT_EQ("Winner", trial->group_name()); 197 EXPECT_EQ("Some_name", trial->name()); 198 199 trial = FieldTrialList::Find("xxx"); 200 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); 201 EXPECT_EQ("yyyy", trial->group_name()); 202 EXPECT_EQ("xxx", trial->name()); 203} 204 205TEST_F(FieldTrialTest, BogusRestore) { 206 EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingSlash")); 207 EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingGroupName/")); 208 EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingFinalSlash/gname")); 209 EXPECT_FALSE(FieldTrialList::StringAugmentsState("/noname, only group/")); 210} 211 212TEST_F(FieldTrialTest, DuplicateRestore) { 213 FieldTrial* trial = new FieldTrial("Some name", 10); 214 trial->AppendGroup("Winner", 10); 215 std::string save_string; 216 FieldTrialList::StatesToString(&save_string); 217 EXPECT_EQ("Some name/Winner/", save_string); 218 219 // It is OK if we redundantly specify a winner. 220 EXPECT_TRUE(FieldTrialList::StringAugmentsState(save_string)); 221 222 // But it is an error to try to change to a different winner. 223 EXPECT_FALSE(FieldTrialList::StringAugmentsState("Some name/Loser/")); 224} 225 226TEST_F(FieldTrialTest, MakeName) { 227 FieldTrial* trial = new FieldTrial("Field Trial", 10); 228 trial->AppendGroup("Winner", 10); 229 EXPECT_EQ("Histogram_Winner", 230 FieldTrial::MakeName("Histogram", "Field Trial")); 231} 232 233} // namespace base 234