Make castv2 performance test work.
[chromium-blink-merge.git] / components / variations / variations_seed_processor_unittest.cc
blob147bf6021c1422390003663f02ea298b9c1981ec
1 // Copyright 2013 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.
5 #include "components/variations/variations_seed_processor.h"
7 #include <map>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/variations/processed_study.h"
15 #include "components/variations/variations_associated_data.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 namespace variations {
20 namespace {
22 // Converts |time| to Study proto format.
23 int64 TimeToProtoTime(const base::Time& time) {
24 return (time - base::Time::UnixEpoch()).InSeconds();
27 // Constants for testing associating command line flags with trial groups.
28 const char kFlagStudyName[] = "flag_test_trial";
29 const char kFlagGroup1Name[] = "flag_group1";
30 const char kFlagGroup2Name[] = "flag_group2";
31 const char kNonFlagGroupName[] = "non_flag_group";
32 const char kForcingFlag1[] = "flag_test1";
33 const char kForcingFlag2[] = "flag_test2";
35 const VariationID kExperimentId = 123;
37 // Adds an experiment to |study| with the specified |name| and |probability|.
38 Study_Experiment* AddExperiment(const std::string& name, int probability,
39 Study* study) {
40 Study_Experiment* experiment = study->add_experiment();
41 experiment->set_name(name);
42 experiment->set_probability_weight(probability);
43 return experiment;
46 // Populates |study| with test data used for testing associating command line
47 // flags with trials groups. The study will contain three groups, a default
48 // group that isn't associated with a flag, and two other groups, both
49 // associated with different flags.
50 Study CreateStudyWithFlagGroups(int default_group_probability,
51 int flag_group1_probability,
52 int flag_group2_probability) {
53 DCHECK_GE(default_group_probability, 0);
54 DCHECK_GE(flag_group1_probability, 0);
55 DCHECK_GE(flag_group2_probability, 0);
56 Study study;
57 study.set_name(kFlagStudyName);
58 study.set_default_experiment_name(kNonFlagGroupName);
60 AddExperiment(kNonFlagGroupName, default_group_probability, &study);
61 AddExperiment(kFlagGroup1Name, flag_group1_probability, &study)
62 ->set_forcing_flag(kForcingFlag1);
63 AddExperiment(kFlagGroup2Name, flag_group2_probability, &study)
64 ->set_forcing_flag(kForcingFlag2);
66 return study;
69 // Tests whether a field trial is active (i.e. group() has been called on it).
70 bool IsFieldTrialActive(const std::string& trial_name) {
71 base::FieldTrial::ActiveGroups active_groups;
72 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
73 for (size_t i = 0; i < active_groups.size(); ++i) {
74 if (active_groups[i].trial_name == trial_name)
75 return true;
77 return false;
80 class TestOverrideStringCallback {
81 public:
82 typedef std::map<uint32_t, base::string16> OverrideMap;
84 TestOverrideStringCallback()
85 : callback_(base::Bind(&TestOverrideStringCallback::Override,
86 base::Unretained(this))) {}
88 virtual ~TestOverrideStringCallback() {}
90 const VariationsSeedProcessor::UIStringOverrideCallback& callback() const {
91 return callback_;
94 const OverrideMap& overrides() const { return overrides_; }
96 private:
97 void Override(uint32_t hash, const base::string16& string) {
98 overrides_[hash] = string;
101 VariationsSeedProcessor::UIStringOverrideCallback callback_;
102 OverrideMap overrides_;
104 DISALLOW_COPY_AND_ASSIGN(TestOverrideStringCallback);
107 } // namespace
109 class VariationsSeedProcessorTest : public ::testing::Test {
110 public:
111 VariationsSeedProcessorTest() {
114 ~VariationsSeedProcessorTest() override {
115 // Ensure that the maps are cleared between tests, since they are stored as
116 // process singletons.
117 testing::ClearAllVariationIDs();
118 testing::ClearAllVariationParams();
121 bool CreateTrialFromStudy(const Study* study) {
122 ProcessedStudy processed_study;
123 if (processed_study.Init(study, false)) {
124 VariationsSeedProcessor().CreateTrialFromStudy(
125 processed_study, override_callback_.callback());
126 return true;
128 return false;
131 protected:
132 TestOverrideStringCallback override_callback_;
134 private:
135 DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessorTest);
138 TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) {
139 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
141 base::FieldTrialList field_trial_list(NULL);
143 Study study = CreateStudyWithFlagGroups(100, 0, 0);
144 study.mutable_experiment(1)->set_google_web_experiment_id(kExperimentId);
146 EXPECT_TRUE(CreateTrialFromStudy(&study));
147 EXPECT_EQ(kFlagGroup1Name,
148 base::FieldTrialList::FindFullName(kFlagStudyName));
150 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName,
151 kFlagGroup1Name);
152 EXPECT_EQ(kExperimentId, id);
155 // Test that the group for kForcingFlag1 is forced.
156 TEST_F(VariationsSeedProcessorTest, ForceGroupWithFlag1) {
157 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
159 base::FieldTrialList field_trial_list(NULL);
161 Study study = CreateStudyWithFlagGroups(100, 0, 0);
162 EXPECT_TRUE(CreateTrialFromStudy(&study));
163 EXPECT_EQ(kFlagGroup1Name,
164 base::FieldTrialList::FindFullName(kFlagStudyName));
167 // Test that the group for kForcingFlag2 is forced.
168 TEST_F(VariationsSeedProcessorTest, ForceGroupWithFlag2) {
169 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag2);
171 base::FieldTrialList field_trial_list(NULL);
173 Study study = CreateStudyWithFlagGroups(100, 0, 0);
174 EXPECT_TRUE(CreateTrialFromStudy(&study));
175 EXPECT_EQ(kFlagGroup2Name,
176 base::FieldTrialList::FindFullName(kFlagStudyName));
179 TEST_F(VariationsSeedProcessorTest, ForceGroup_ChooseFirstGroupWithFlag) {
180 // Add the flag to the command line arguments so the flag group is forced.
181 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
182 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag2);
184 base::FieldTrialList field_trial_list(NULL);
186 Study study = CreateStudyWithFlagGroups(100, 0, 0);
187 EXPECT_TRUE(CreateTrialFromStudy(&study));
188 EXPECT_EQ(kFlagGroup1Name,
189 base::FieldTrialList::FindFullName(kFlagStudyName));
192 TEST_F(VariationsSeedProcessorTest, ForceGroup_DontChooseGroupWithFlag) {
193 base::FieldTrialList field_trial_list(NULL);
195 // The two flag groups are given high probability, which would normally make
196 // them very likely to be chosen. They won't be chosen since flag groups are
197 // never chosen when their flag isn't present.
198 Study study = CreateStudyWithFlagGroups(1, 999, 999);
199 EXPECT_TRUE(CreateTrialFromStudy(&study));
200 EXPECT_EQ(kNonFlagGroupName,
201 base::FieldTrialList::FindFullName(kFlagStudyName));
204 TEST_F(VariationsSeedProcessorTest,
205 NonExpiredStudyPrioritizedOverExpiredStudy) {
206 VariationsSeedProcessor seed_processor;
208 const std::string kTrialName = "A";
209 const std::string kGroup1Name = "Group1";
211 VariationsSeed seed;
212 Study* study1 = seed.add_study();
213 study1->set_name(kTrialName);
214 study1->set_default_experiment_name("Default");
215 AddExperiment(kGroup1Name, 100, study1);
216 AddExperiment("Default", 0, study1);
217 Study* study2 = seed.add_study();
218 *study2 = *study1;
219 ASSERT_EQ(seed.study(0).name(), seed.study(1).name());
221 const base::Time year_ago =
222 base::Time::Now() - base::TimeDelta::FromDays(365);
224 const base::Version version("20.0.0.0");
226 // Check that adding [expired, non-expired] activates the non-expired one.
227 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
229 base::FieldTrialList field_trial_list(NULL);
230 study1->set_expiry_date(TimeToProtoTime(year_ago));
231 seed_processor.CreateTrialsFromSeed(seed,
232 "en-CA",
233 base::Time::Now(),
234 version,
235 Study_Channel_STABLE,
236 Study_FormFactor_DESKTOP,
238 override_callback_.callback());
239 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
242 // Check that adding [non-expired, expired] activates the non-expired one.
243 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
245 base::FieldTrialList field_trial_list(NULL);
246 study1->clear_expiry_date();
247 study2->set_expiry_date(TimeToProtoTime(year_ago));
248 seed_processor.CreateTrialsFromSeed(seed,
249 "en-CA",
250 base::Time::Now(),
251 version,
252 Study_Channel_STABLE,
253 Study_FormFactor_DESKTOP,
255 override_callback_.callback());
256 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
260 TEST_F(VariationsSeedProcessorTest, OverrideUIStrings) {
261 base::FieldTrialList field_trial_list(NULL);
263 Study study;
264 study.set_name("Study1");
265 study.set_default_experiment_name("B");
266 study.set_activation_type(Study_ActivationType_ACTIVATION_AUTO);
268 Study_Experiment* experiment1 = AddExperiment("A", 0, &study);
269 Study_Experiment_OverrideUIString* override =
270 experiment1->add_override_ui_string();
272 override->set_name_hash(1234);
273 override->set_value("test");
275 Study_Experiment* experiment2 = AddExperiment("B", 1, &study);
277 EXPECT_TRUE(CreateTrialFromStudy(&study));
279 const TestOverrideStringCallback::OverrideMap& overrides =
280 override_callback_.overrides();
282 EXPECT_TRUE(overrides.empty());
284 study.set_name("Study2");
285 experiment1->set_probability_weight(1);
286 experiment2->set_probability_weight(0);
288 EXPECT_TRUE(CreateTrialFromStudy(&study));
290 EXPECT_EQ(1u, overrides.size());
291 TestOverrideStringCallback::OverrideMap::const_iterator it =
292 overrides.find(1234);
293 EXPECT_EQ(base::ASCIIToUTF16("test"), it->second);
296 TEST_F(VariationsSeedProcessorTest, OverrideUIStringsWithForcingFlag) {
297 Study study = CreateStudyWithFlagGroups(100, 0, 0);
298 ASSERT_EQ(kForcingFlag1, study.experiment(1).forcing_flag());
300 study.set_activation_type(Study_ActivationType_ACTIVATION_AUTO);
301 Study_Experiment_OverrideUIString* override =
302 study.mutable_experiment(1)->add_override_ui_string();
303 override->set_name_hash(1234);
304 override->set_value("test");
306 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
307 base::FieldTrialList field_trial_list(NULL);
308 EXPECT_TRUE(CreateTrialFromStudy(&study));
309 EXPECT_EQ(kFlagGroup1Name, base::FieldTrialList::FindFullName(study.name()));
311 const TestOverrideStringCallback::OverrideMap& overrides =
312 override_callback_.overrides();
313 EXPECT_EQ(1u, overrides.size());
314 TestOverrideStringCallback::OverrideMap::const_iterator it =
315 overrides.find(1234);
316 EXPECT_EQ(base::ASCIIToUTF16("test"), it->second);
319 TEST_F(VariationsSeedProcessorTest, ValidateStudy) {
320 Study study;
321 study.set_default_experiment_name("def");
322 AddExperiment("abc", 100, &study);
323 Study_Experiment* default_group = AddExperiment("def", 200, &study);
325 ProcessedStudy processed_study;
326 EXPECT_TRUE(processed_study.Init(&study, false));
327 EXPECT_EQ(300, processed_study.total_probability());
328 EXPECT_FALSE(processed_study.all_assignments_to_one_group());
330 // Min version checks.
331 study.mutable_filter()->set_min_version("1.2.3.*");
332 EXPECT_TRUE(processed_study.Init(&study, false));
333 study.mutable_filter()->set_min_version("1.*.3");
334 EXPECT_FALSE(processed_study.Init(&study, false));
335 study.mutable_filter()->set_min_version("1.2.3");
336 EXPECT_TRUE(processed_study.Init(&study, false));
338 // Max version checks.
339 study.mutable_filter()->set_max_version("2.3.4.*");
340 EXPECT_TRUE(processed_study.Init(&study, false));
341 study.mutable_filter()->set_max_version("*.3");
342 EXPECT_FALSE(processed_study.Init(&study, false));
343 study.mutable_filter()->set_max_version("2.3.4");
344 EXPECT_TRUE(processed_study.Init(&study, false));
346 study.clear_default_experiment_name();
347 EXPECT_FALSE(processed_study.Init(&study, false));
349 study.set_default_experiment_name("xyz");
350 EXPECT_FALSE(processed_study.Init(&study, false));
352 study.set_default_experiment_name("def");
353 default_group->clear_name();
354 EXPECT_FALSE(processed_study.Init(&study, false));
356 default_group->set_name("def");
357 EXPECT_TRUE(processed_study.Init(&study, false));
358 Study_Experiment* repeated_group = study.add_experiment();
359 repeated_group->set_name("abc");
360 repeated_group->set_probability_weight(1);
361 EXPECT_FALSE(processed_study.Init(&study, false));
364 TEST_F(VariationsSeedProcessorTest, ProcessedStudyAllAssignmentsToOneGroup) {
365 Study study;
366 study.set_default_experiment_name("def");
367 AddExperiment("def", 100, &study);
369 ProcessedStudy processed_study;
370 EXPECT_TRUE(processed_study.Init(&study, false));
371 EXPECT_TRUE(processed_study.all_assignments_to_one_group());
373 AddExperiment("abc", 0, &study);
374 AddExperiment("flag", 0, &study)->set_forcing_flag(kForcingFlag1);
375 EXPECT_TRUE(processed_study.Init(&study, false));
376 EXPECT_TRUE(processed_study.all_assignments_to_one_group());
378 AddExperiment("xyz", 1, &study);
379 EXPECT_TRUE(processed_study.Init(&study, false));
380 EXPECT_FALSE(processed_study.all_assignments_to_one_group());
382 // Try with default group and first group being at 0.
383 Study study2;
384 study2.set_default_experiment_name("def");
385 AddExperiment("def", 0, &study2);
386 AddExperiment("xyz", 34, &study2);
387 EXPECT_TRUE(processed_study.Init(&study2, false));
388 EXPECT_TRUE(processed_study.all_assignments_to_one_group());
389 AddExperiment("abc", 12, &study2);
390 EXPECT_TRUE(processed_study.Init(&study2, false));
391 EXPECT_FALSE(processed_study.all_assignments_to_one_group());
394 TEST_F(VariationsSeedProcessorTest, VariationParams) {
395 base::FieldTrialList field_trial_list(NULL);
397 Study study;
398 study.set_name("Study1");
399 study.set_default_experiment_name("B");
401 Study_Experiment* experiment1 = AddExperiment("A", 1, &study);
402 Study_Experiment_Param* param = experiment1->add_param();
403 param->set_name("x");
404 param->set_value("y");
406 Study_Experiment* experiment2 = AddExperiment("B", 0, &study);
408 EXPECT_TRUE(CreateTrialFromStudy(&study));
409 EXPECT_EQ("y", GetVariationParamValue("Study1", "x"));
411 study.set_name("Study2");
412 experiment1->set_probability_weight(0);
413 experiment2->set_probability_weight(1);
414 EXPECT_TRUE(CreateTrialFromStudy(&study));
415 EXPECT_EQ(std::string(), GetVariationParamValue("Study2", "x"));
418 TEST_F(VariationsSeedProcessorTest, VariationParamsWithForcingFlag) {
419 Study study = CreateStudyWithFlagGroups(100, 0, 0);
420 ASSERT_EQ(kForcingFlag1, study.experiment(1).forcing_flag());
421 Study_Experiment_Param* param = study.mutable_experiment(1)->add_param();
422 param->set_name("x");
423 param->set_value("y");
425 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
426 base::FieldTrialList field_trial_list(NULL);
427 EXPECT_TRUE(CreateTrialFromStudy(&study));
428 EXPECT_EQ(kFlagGroup1Name, base::FieldTrialList::FindFullName(study.name()));
429 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x"));
432 TEST_F(VariationsSeedProcessorTest, StartsActive) {
433 base::FieldTrialList field_trial_list(NULL);
435 VariationsSeed seed;
436 Study* study1 = seed.add_study();
437 study1->set_name("A");
438 study1->set_default_experiment_name("Default");
439 AddExperiment("AA", 100, study1);
440 AddExperiment("Default", 0, study1);
442 Study* study2 = seed.add_study();
443 study2->set_name("B");
444 study2->set_default_experiment_name("Default");
445 AddExperiment("BB", 100, study2);
446 AddExperiment("Default", 0, study2);
447 study2->set_activation_type(Study_ActivationType_ACTIVATION_AUTO);
449 Study* study3 = seed.add_study();
450 study3->set_name("C");
451 study3->set_default_experiment_name("Default");
452 AddExperiment("CC", 100, study3);
453 AddExperiment("Default", 0, study3);
454 study3->set_activation_type(Study_ActivationType_ACTIVATION_EXPLICIT);
456 VariationsSeedProcessor seed_processor;
457 seed_processor.CreateTrialsFromSeed(seed,
458 "en-CA",
459 base::Time::Now(),
460 base::Version("20.0.0.0"),
461 Study_Channel_STABLE,
462 Study_FormFactor_DESKTOP,
464 override_callback_.callback());
466 // Non-specified and ACTIVATION_EXPLICIT should not start active, but
467 // ACTIVATION_AUTO should.
468 EXPECT_FALSE(IsFieldTrialActive("A"));
469 EXPECT_TRUE(IsFieldTrialActive("B"));
470 EXPECT_FALSE(IsFieldTrialActive("C"));
472 EXPECT_EQ("AA", base::FieldTrialList::FindFullName("A"));
473 EXPECT_EQ("BB", base::FieldTrialList::FindFullName("B"));
474 EXPECT_EQ("CC", base::FieldTrialList::FindFullName("C"));
476 // Now, all studies should be active.
477 EXPECT_TRUE(IsFieldTrialActive("A"));
478 EXPECT_TRUE(IsFieldTrialActive("B"));
479 EXPECT_TRUE(IsFieldTrialActive("C"));
482 TEST_F(VariationsSeedProcessorTest, StartsActiveWithFlag) {
483 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
485 base::FieldTrialList field_trial_list(NULL);
487 Study study = CreateStudyWithFlagGroups(100, 0, 0);
488 study.set_activation_type(Study_ActivationType_ACTIVATION_AUTO);
490 EXPECT_TRUE(CreateTrialFromStudy(&study));
491 EXPECT_TRUE(IsFieldTrialActive(kFlagStudyName));
493 EXPECT_EQ(kFlagGroup1Name,
494 base::FieldTrialList::FindFullName(kFlagStudyName));
497 TEST_F(VariationsSeedProcessorTest, ForcingFlagAlreadyForced) {
498 Study study = CreateStudyWithFlagGroups(100, 0, 0);
499 ASSERT_EQ(kNonFlagGroupName, study.experiment(0).name());
500 Study_Experiment_Param* param = study.mutable_experiment(0)->add_param();
501 param->set_name("x");
502 param->set_value("y");
503 study.mutable_experiment(0)->set_google_web_experiment_id(kExperimentId);
505 base::FieldTrialList field_trial_list(NULL);
506 base::FieldTrialList::CreateFieldTrial(kFlagStudyName, kNonFlagGroupName);
508 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
509 EXPECT_TRUE(CreateTrialFromStudy(&study));
510 // The previously forced experiment should still hold.
511 EXPECT_EQ(kNonFlagGroupName,
512 base::FieldTrialList::FindFullName(study.name()));
514 // Check that params and experiment ids correspond.
515 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x"));
516 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName,
517 kNonFlagGroupName);
518 EXPECT_EQ(kExperimentId, id);
521 } // namespace variations