OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Test of FieldTrial class | 5 // Test of FieldTrial class |
6 | 6 |
7 #include "base/metrics/field_trial.h" | 7 #include "base/metrics/field_trial.h" |
8 | 8 |
9 #include "base/rand_util.h" | |
9 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
11 #include "base/string_number_conversions.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
11 | 13 |
14 #include <limits> | |
15 | |
12 namespace base { | 16 namespace base { |
13 | 17 |
14 class FieldTrialTest : public testing::Test { | 18 class FieldTrialTest : public testing::Test { |
15 public: | 19 public: |
16 FieldTrialTest() : trial_list_() { | 20 FieldTrialTest() : trial_list_("client_id") { |
17 Time now = Time::NowFromSystemTime(); | 21 Time now = Time::NowFromSystemTime(); |
18 TimeDelta oneYear = TimeDelta::FromDays(365); | 22 TimeDelta oneYear = TimeDelta::FromDays(365); |
19 Time::Exploded exploded; | 23 Time::Exploded exploded; |
20 | 24 |
21 Time next_year_time = now + oneYear; | 25 Time next_year_time = now + oneYear; |
22 next_year_time.LocalExplode(&exploded); | 26 next_year_time.LocalExplode(&exploded); |
23 next_year_ = exploded.year; | 27 next_year_ = exploded.year; |
24 | 28 |
25 Time last_year_time = now - oneYear; | 29 Time last_year_time = now - oneYear; |
26 last_year_time.LocalExplode(&exploded); | 30 last_year_time.LocalExplode(&exploded); |
27 last_year_ = exploded.year; | 31 last_year_ = exploded.year; |
28 } | 32 } |
29 | 33 |
34 void SetClientId(const std::string& client_id) { | |
35 trial_list_.client_id_ = client_id; | |
36 } | |
37 | |
38 void DoSaveTest(); | |
39 void DoRestoreTest(const std::string& restored_client_id); | |
40 | |
30 protected: | 41 protected: |
31 int next_year_; | 42 int next_year_; |
32 int last_year_; | 43 int last_year_; |
33 | 44 |
34 private: | 45 private: |
35 FieldTrialList trial_list_; | 46 FieldTrialList trial_list_; |
36 }; | 47 }; |
37 | 48 |
38 // Test registration, and also check that destructors are called for trials | 49 // Test registration, and also check that destructors are called for trials |
39 // (and that Purify doesn't catch us leaking). | 50 // (and that Purify doesn't catch us leaking). |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
210 name, 1000000000, default_group_name, last_year_, 1, 1); | 221 name, 1000000000, default_group_name, last_year_, 1, 1); |
211 trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen. | 222 trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen. |
212 | 223 |
213 // Because trial has expired, we should always be in the default group. | 224 // Because trial has expired, we should always be in the default group. |
214 EXPECT_EQ(FieldTrial::kDefaultGroupNumber, trial->group()); | 225 EXPECT_EQ(FieldTrial::kDefaultGroupNumber, trial->group()); |
215 | 226 |
216 // And that default_group_name should ALWAYS win. | 227 // And that default_group_name should ALWAYS win. |
217 EXPECT_EQ(default_group_name, trial->group_name()); | 228 EXPECT_EQ(default_group_name, trial->group_name()); |
218 } | 229 } |
219 | 230 |
220 TEST_F(FieldTrialTest, Save) { | 231 void FieldTrialTest::DoSaveTest() { |
232 const std::string& client_id = FieldTrialList::client_id(); | |
221 std::string save_string; | 233 std::string save_string; |
222 | 234 |
223 FieldTrial* trial = | 235 FieldTrial* trial = |
224 new FieldTrial( | 236 new FieldTrial( |
225 "Some name", 10, "Default some name", next_year_, 12, 31); | 237 "Some name", 10, "Default some name", next_year_, 12, 31); |
226 // There is no winner yet, so no textual group name is associated with trial. | 238 // There is no winner yet, so no textual group name is associated with trial. |
227 EXPECT_EQ("", trial->group_name_internal()); | 239 EXPECT_EQ("", trial->group_name_internal()); |
228 FieldTrialList::StatesToString(&save_string); | 240 FieldTrialList::StatesToString(&save_string); |
229 EXPECT_EQ("Some name/Default some name/", save_string); | 241 EXPECT_EQ(client_id + "/Some name/Default some name/", save_string); |
jar (doing other things)
2011/05/03 00:17:47
Warning: This test may need to change if we stop d
Jói
2011/05/03 17:41:47
Done.
| |
230 save_string.clear(); | 242 save_string.clear(); |
231 | 243 |
232 // Create a winning group. | 244 // Create a winning group. |
233 trial->AppendGroup("Winner", 10); | 245 trial->AppendGroup("Winner", 10); |
234 FieldTrialList::StatesToString(&save_string); | 246 FieldTrialList::StatesToString(&save_string); |
235 EXPECT_EQ("Some name/Winner/", save_string); | 247 EXPECT_EQ(client_id + "/Some name/Winner/", save_string); |
236 save_string.clear(); | 248 save_string.clear(); |
237 | 249 |
238 // Create a second trial and winning group. | 250 // Create a second trial and winning group. |
239 FieldTrial* trial2 = | 251 FieldTrial* trial2 = |
240 new FieldTrial("xxx", 10, "Default xxx", next_year_, 12, 31); | 252 new FieldTrial("xxx", 10, "Default xxx", next_year_, 12, 31); |
241 trial2->AppendGroup("yyyy", 10); | 253 trial2->AppendGroup("yyyy", 10); |
242 | 254 |
243 FieldTrialList::StatesToString(&save_string); | 255 FieldTrialList::StatesToString(&save_string); |
244 // We assume names are alphabetized... though this is not critical. | 256 // We assume names are alphabetized... though this is not critical. |
245 EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string); | 257 EXPECT_EQ(client_id + "/Some name/Winner/xxx/yyyy/", save_string); |
246 } | 258 } |
247 | 259 |
248 TEST_F(FieldTrialTest, Restore) { | 260 TEST_F(FieldTrialTest, Save) { |
261 DoSaveTest(); | |
262 } | |
263 | |
264 TEST_F(FieldTrialTest, SaveWithEmptyClientId) { | |
265 SetClientId(""); | |
266 DoSaveTest(); | |
267 } | |
268 | |
269 void FieldTrialTest::DoRestoreTest(const std::string& restored_client_id) { | |
249 EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL); | 270 EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL); |
250 EXPECT_TRUE(FieldTrialList::Find("xxx") == NULL); | 271 EXPECT_TRUE(FieldTrialList::Find("xxx") == NULL); |
251 | 272 |
252 FieldTrialList::CreateTrialsInChildProcess("Some_name/Winner/xxx/yyyy/"); | 273 FieldTrialList::CreateTrialsInChildProcess( |
274 restored_client_id + "/Some_name/Winner/xxx/yyyy/"); | |
275 EXPECT_EQ(restored_client_id, FieldTrialList::client_id()); | |
253 | 276 |
254 FieldTrial* trial = FieldTrialList::Find("Some_name"); | 277 FieldTrial* trial = FieldTrialList::Find("Some_name"); |
255 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); | 278 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); |
256 EXPECT_EQ("Winner", trial->group_name()); | 279 EXPECT_EQ("Winner", trial->group_name()); |
257 EXPECT_EQ("Some_name", trial->name()); | 280 EXPECT_EQ("Some_name", trial->name()); |
258 | 281 |
259 trial = FieldTrialList::Find("xxx"); | 282 trial = FieldTrialList::Find("xxx"); |
260 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); | 283 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); |
261 EXPECT_EQ("yyyy", trial->group_name()); | 284 EXPECT_EQ("yyyy", trial->group_name()); |
262 EXPECT_EQ("xxx", trial->name()); | 285 EXPECT_EQ("xxx", trial->name()); |
263 } | 286 } |
264 | 287 |
288 TEST_F(FieldTrialTest, Restore) { | |
289 DoRestoreTest("restored_client_id"); | |
290 } | |
291 | |
292 TEST_F(FieldTrialTest, RestoreWithEmptyClientId) { | |
293 DoRestoreTest(""); | |
294 } | |
295 | |
265 TEST_F(FieldTrialTest, BogusRestore) { | 296 TEST_F(FieldTrialTest, BogusRestore) { |
266 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingSlash")); | 297 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess( |
267 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingGroupName/")); | 298 "restored_client_id/MissingSlash")); |
268 EXPECT_FALSE( | 299 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess( |
269 FieldTrialList::CreateTrialsInChildProcess("MissingFinalSlash/gname")); | 300 "restored_client_id/MissingGroupName/")); |
270 EXPECT_FALSE( | 301 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess( |
271 FieldTrialList::CreateTrialsInChildProcess("/noname, only group/")); | 302 "restored_client_id/MissingFinalSlash/gname")); |
303 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess( | |
304 "restored_client_id/noname, only group/")); | |
272 } | 305 } |
273 | 306 |
274 TEST_F(FieldTrialTest, DuplicateRestore) { | 307 TEST_F(FieldTrialTest, DuplicateRestore) { |
275 FieldTrial* trial = | 308 FieldTrial* trial = |
276 new FieldTrial( | 309 new FieldTrial( |
277 "Some name", 10, "Default some name", next_year_, 12, 31); | 310 "Some name", 10, "Default some name", next_year_, 12, 31); |
278 trial->AppendGroup("Winner", 10); | 311 trial->AppendGroup("Winner", 10); |
279 std::string save_string; | 312 std::string save_string; |
280 FieldTrialList::StatesToString(&save_string); | 313 FieldTrialList::StatesToString(&save_string); |
281 EXPECT_EQ("Some name/Winner/", save_string); | 314 EXPECT_EQ("client_id/Some name/Winner/", save_string); |
282 | 315 |
283 // It is OK if we redundantly specify a winner. | 316 // It is OK if we redundantly specify a winner. |
284 EXPECT_TRUE(FieldTrialList::CreateTrialsInChildProcess(save_string)); | 317 EXPECT_TRUE(FieldTrialList::CreateTrialsInChildProcess(save_string)); |
285 | 318 |
286 // But it is an error to try to change to a different winner. | 319 // But it is an error to try to change to a different winner. |
287 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("Some name/Loser/")); | 320 EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess( |
321 "client_id/Some name/Loser/")); | |
288 } | 322 } |
289 | 323 |
290 TEST_F(FieldTrialTest, CreateFieldTrial) { | 324 TEST_F(FieldTrialTest, CreateFieldTrial) { |
291 EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL); | 325 EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL); |
292 | 326 |
293 FieldTrialList::CreateFieldTrial("Some_name", "Winner"); | 327 FieldTrialList::CreateFieldTrial("Some_name", "Winner"); |
294 | 328 |
295 FieldTrial* trial = FieldTrialList::Find("Some_name"); | 329 FieldTrial* trial = FieldTrialList::Find("Some_name"); |
296 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); | 330 ASSERT_NE(static_cast<FieldTrial*>(NULL), trial); |
297 EXPECT_EQ("Winner", trial->group_name()); | 331 EXPECT_EQ("Winner", trial->group_name()); |
(...skipping 16 matching lines...) Expand all Loading... | |
314 } | 348 } |
315 | 349 |
316 TEST_F(FieldTrialTest, MakeName) { | 350 TEST_F(FieldTrialTest, MakeName) { |
317 FieldTrial* trial = | 351 FieldTrial* trial = |
318 new FieldTrial("Field Trial", 10, "Winner", next_year_, 12, 31); | 352 new FieldTrial("Field Trial", 10, "Winner", next_year_, 12, 31); |
319 trial->group(); | 353 trial->group(); |
320 EXPECT_EQ("Histogram_Winner", | 354 EXPECT_EQ("Histogram_Winner", |
321 FieldTrial::MakeName("Histogram", "Field Trial")); | 355 FieldTrial::MakeName("Histogram", "Field Trial")); |
322 } | 356 } |
323 | 357 |
358 TEST_F(FieldTrialTest, HashClientId) { | |
359 double results[] = { | |
360 FieldTrial::HashClientId("hi", "1"), | |
361 FieldTrial::HashClientId("there", "1"), | |
362 }; | |
363 ASSERT_NE(results[0], results[1]); | |
364 for (size_t i = 0; i < arraysize(results); ++i) { | |
365 ASSERT_LE(0.0, results[i]); | |
366 ASSERT_GT(1.0, results[i]); | |
367 } | |
368 | |
369 ASSERT_EQ(FieldTrial::HashClientId("yo", "1"), | |
370 FieldTrial::HashClientId("yo", "1")); | |
371 ASSERT_NE(FieldTrial::HashClientId("yo", "something"), | |
372 FieldTrial::HashClientId("yo", "else")); | |
373 } | |
374 | |
375 TEST_F(FieldTrialTest, HashClientIdIsUniform) { | |
376 // Choose a random start number but go sequentially from there, so | |
377 // that each test tries a different range but we never provide uniformly | |
378 // distributed input data. | |
379 int current_number = RandInt(0, std::numeric_limits<int>::max()); | |
380 | |
381 // The expected value of a random distribution is the average over all | |
382 // samples as the number of samples approaches infinity. For a uniform | |
383 // distribution from [0.0, 1.0) this would be 0.5. | |
384 // | |
385 // We do kSamplesBetweenChecks at a time and check if the value has converged | |
386 // to a narrow interval around 0.5. A non-uniform distribution would likely | |
387 // converge at something different, or not converge consistently within this | |
388 // range (i.e. the test would start timing out occasionally). | |
389 int kSamplesBetweenChecks = 300; | |
390 int num_samples = 0; | |
391 double total_value = 0.0; | |
392 while (true) { | |
393 for (int i = 0; i < kSamplesBetweenChecks; ++i) { | |
394 total_value += FieldTrial::HashClientId( | |
395 IntToString(current_number++), "salt"); | |
396 num_samples++; | |
397 } | |
398 | |
399 double average = total_value / num_samples; | |
400 double kExpectedMin = 0.48; | |
401 double kExpectedMax = 0.52; | |
402 | |
403 if (num_samples > 1000 && | |
404 (average < kExpectedMin || average > kExpectedMax)) { | |
405 // Only printed once we have enough samples that it's very unlikely | |
406 // things haven't converged. | |
407 printf("After %d samples, the average was %f, outside the expected\n" | |
408 "range (%f, %f). We will add more samples and check after every\n" | |
409 "%d samples. If the average does not converge, something\n" | |
410 "is broken. If it does converge, the test will pass.\n", | |
411 num_samples, average, | |
412 kExpectedMin, kExpectedMax, kSamplesBetweenChecks); | |
413 } else { | |
414 // Success. | |
415 break; | |
416 } | |
417 } | |
418 } | |
419 | |
420 TEST_F(FieldTrialTest, UseOneTimeRandomization) { | |
421 // Simply asserts that two trials using one-time randomization | |
422 // that have different names, normally generate different results. | |
423 // | |
424 // Note that depending on the one-time random initialization, they | |
425 // _might_ actually give the same result, but we know that given | |
426 // the particular client_id we use for unit tests they won't. | |
427 scoped_refptr<FieldTrial> trials[] = { | |
428 new FieldTrial("one", 100, "default", next_year_, 1, 1), | |
429 new FieldTrial("two", 100, "default", next_year_, 1, 1), | |
430 }; | |
431 | |
432 for (size_t i = 0; i < arraysize(trials); ++i) { | |
433 trials[i]->UseOneTimeRandomization(); | |
434 | |
435 for (int j = 0; j < 100; ++j) { | |
436 trials[i]->AppendGroup("", 1); | |
437 } | |
438 } | |
439 | |
440 // The trials are most likely to give different results since they have | |
441 // different names. | |
442 ASSERT_NE(trials[0]->group(), trials[1]->group()); | |
443 ASSERT_NE(trials[0]->group_name(), trials[1]->group_name()); | |
444 } | |
445 | |
446 TEST_F(FieldTrialTest, DisableImmediately) { | |
447 FieldTrial* trial = | |
448 new FieldTrial("trial", 100, "default", next_year_, 12, 31); | |
449 trial->Disable(); | |
450 ASSERT_EQ("default", trial->group_name()); | |
451 ASSERT_EQ(FieldTrial::kDefaultGroupNumber, trial->group()); | |
452 } | |
453 | |
454 TEST_F(FieldTrialTest, DisableAfterInitialization) { | |
455 FieldTrial* trial = | |
456 new FieldTrial("trial", 100, "default", next_year_, 12, 31); | |
457 trial->AppendGroup("non_default", 100); | |
458 ASSERT_EQ("non_default", trial->group_name()); | |
459 trial->Disable(); | |
460 ASSERT_EQ("default", trial->group_name()); | |
461 } | |
462 | |
324 } // namespace base | 463 } // namespace base |
OLD | NEW |