Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: components/variations/variations_seed_processor_unittest.cc

Issue 1306653004: Expand FeatureList to support FieldTrial association. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/variations/variations_seed_processor.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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 #include "components/variations/variations_seed_processor.h" 5 #include "components/variations/variations_seed_processor.h"
6 6
7 #include <map> 7 #include <map>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/feature_list.h"
13 #include "base/format_macros.h"
12 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
15 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
14 #include "components/variations/processed_study.h" 17 #include "components/variations/processed_study.h"
15 #include "components/variations/variations_associated_data.h" 18 #include "components/variations/variations_associated_data.h"
16 #include "testing/gtest/include/gtest/gtest.h" 19 #include "testing/gtest/include/gtest/gtest.h"
17 20
18 namespace variations { 21 namespace variations {
19 22
20 namespace { 23 namespace {
21 24
22 // Converts |time| to Study proto format. 25 // Converts |time| to Study proto format.
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 class VariationsSeedProcessorTest : public ::testing::Test { 101 class VariationsSeedProcessorTest : public ::testing::Test {
99 public: 102 public:
100 VariationsSeedProcessorTest() { 103 VariationsSeedProcessorTest() {
101 } 104 }
102 105
103 ~VariationsSeedProcessorTest() override { 106 ~VariationsSeedProcessorTest() override {
104 // Ensure that the maps are cleared between tests, since they are stored as 107 // Ensure that the maps are cleared between tests, since they are stored as
105 // process singletons. 108 // process singletons.
106 testing::ClearAllVariationIDs(); 109 testing::ClearAllVariationIDs();
107 testing::ClearAllVariationParams(); 110 testing::ClearAllVariationParams();
111
112 base::FeatureList::ClearInstanceForTesting();
108 } 113 }
109 114
110 bool CreateTrialFromStudy(const Study* study) { 115 bool CreateTrialFromStudy(const Study* study) {
116 return CreateTrialFromStudyWithFeatureList(study, &feature_list_);
117 }
118
119 bool CreateTrialFromStudyWithFeatureList(const Study* study,
120 base::FeatureList* feature_list) {
111 ProcessedStudy processed_study; 121 ProcessedStudy processed_study;
112 if (processed_study.Init(study, false)) { 122 if (processed_study.Init(study, false)) {
113 VariationsSeedProcessor().CreateTrialFromStudy( 123 VariationsSeedProcessor().CreateTrialFromStudy(
114 processed_study, override_callback_.callback()); 124 processed_study, override_callback_.callback(), feature_list);
115 return true; 125 return true;
116 } 126 }
117 return false; 127 return false;
118 } 128 }
119 129
120 protected: 130 protected:
131 base::FeatureList feature_list_;
121 TestOverrideStringCallback override_callback_; 132 TestOverrideStringCallback override_callback_;
122 133
123 private: 134 private:
124 DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessorTest); 135 DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessorTest);
125 }; 136 };
126 137
127 TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) { 138 TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) {
128 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1); 139 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
129 140
130 base::FieldTrialList field_trial_list(NULL); 141 base::FieldTrialList field_trial_list(NULL);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 ASSERT_EQ(seed.study(0).name(), seed.study(1).name()); 219 ASSERT_EQ(seed.study(0).name(), seed.study(1).name());
209 220
210 const base::Time year_ago = 221 const base::Time year_ago =
211 base::Time::Now() - base::TimeDelta::FromDays(365); 222 base::Time::Now() - base::TimeDelta::FromDays(365);
212 223
213 const base::Version version("20.0.0.0"); 224 const base::Version version("20.0.0.0");
214 225
215 // Check that adding [expired, non-expired] activates the non-expired one. 226 // Check that adding [expired, non-expired] activates the non-expired one.
216 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName)); 227 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
217 { 228 {
229 base::FeatureList feature_list;
218 base::FieldTrialList field_trial_list(NULL); 230 base::FieldTrialList field_trial_list(NULL);
219 study1->set_expiry_date(TimeToProtoTime(year_ago)); 231 study1->set_expiry_date(TimeToProtoTime(year_ago));
220 seed_processor.CreateTrialsFromSeed( 232 seed_processor.CreateTrialsFromSeed(
221 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, 233 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
222 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback()); 234 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
235 &feature_list);
223 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); 236 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
224 } 237 }
225 238
226 // Check that adding [non-expired, expired] activates the non-expired one. 239 // Check that adding [non-expired, expired] activates the non-expired one.
227 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName)); 240 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
228 { 241 {
242 base::FeatureList feature_list;
229 base::FieldTrialList field_trial_list(NULL); 243 base::FieldTrialList field_trial_list(NULL);
230 study1->clear_expiry_date(); 244 study1->clear_expiry_date();
231 study2->set_expiry_date(TimeToProtoTime(year_ago)); 245 study2->set_expiry_date(TimeToProtoTime(year_ago));
232 seed_processor.CreateTrialsFromSeed( 246 seed_processor.CreateTrialsFromSeed(
233 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, 247 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
234 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback()); 248 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
249 &feature_list);
235 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); 250 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
236 } 251 }
237 } 252 }
238 253
239 TEST_F(VariationsSeedProcessorTest, OverrideUIStrings) { 254 TEST_F(VariationsSeedProcessorTest, OverrideUIStrings) {
240 base::FieldTrialList field_trial_list(NULL); 255 base::FieldTrialList field_trial_list(NULL);
241 256
242 Study study; 257 Study study;
243 study.set_name("Study1"); 258 study.set_name("Study1");
244 study.set_default_experiment_name("B"); 259 study.set_default_experiment_name("B");
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 study3->set_name("C"); 444 study3->set_name("C");
430 study3->set_default_experiment_name("Default"); 445 study3->set_default_experiment_name("Default");
431 AddExperiment("CC", 100, study3); 446 AddExperiment("CC", 100, study3);
432 AddExperiment("Default", 0, study3); 447 AddExperiment("Default", 0, study3);
433 study3->set_activation_type(Study_ActivationType_ACTIVATION_EXPLICIT); 448 study3->set_activation_type(Study_ActivationType_ACTIVATION_EXPLICIT);
434 449
435 VariationsSeedProcessor seed_processor; 450 VariationsSeedProcessor seed_processor;
436 seed_processor.CreateTrialsFromSeed( 451 seed_processor.CreateTrialsFromSeed(
437 seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"), 452 seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"),
438 Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", "", "", 453 Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", "", "",
439 override_callback_.callback()); 454 override_callback_.callback(), &feature_list_);
440 455
441 // Non-specified and ACTIVATION_EXPLICIT should not start active, but 456 // Non-specified and ACTIVATION_EXPLICIT should not start active, but
442 // ACTIVATION_AUTO should. 457 // ACTIVATION_AUTO should.
443 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("A")); 458 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("A"));
444 EXPECT_TRUE(base::FieldTrialList::IsTrialActive("B")); 459 EXPECT_TRUE(base::FieldTrialList::IsTrialActive("B"));
445 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("C")); 460 EXPECT_FALSE(base::FieldTrialList::IsTrialActive("C"));
446 461
447 EXPECT_EQ("AA", base::FieldTrialList::FindFullName("A")); 462 EXPECT_EQ("AA", base::FieldTrialList::FindFullName("A"));
448 EXPECT_EQ("BB", base::FieldTrialList::FindFullName("B")); 463 EXPECT_EQ("BB", base::FieldTrialList::FindFullName("B"));
449 EXPECT_EQ("CC", base::FieldTrialList::FindFullName("C")); 464 EXPECT_EQ("CC", base::FieldTrialList::FindFullName("C"));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 EXPECT_EQ(kNonFlagGroupName, 501 EXPECT_EQ(kNonFlagGroupName,
487 base::FieldTrialList::FindFullName(study.name())); 502 base::FieldTrialList::FindFullName(study.name()));
488 503
489 // Check that params and experiment ids correspond. 504 // Check that params and experiment ids correspond.
490 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x")); 505 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x"));
491 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName, 506 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName,
492 kNonFlagGroupName); 507 kNonFlagGroupName);
493 EXPECT_EQ(kExperimentId, id); 508 EXPECT_EQ(kExperimentId, id);
494 } 509 }
495 510
511 TEST_F(VariationsSeedProcessorTest, FeatureEnabledOrDisableByTrial) {
512 struct base::Feature kFeatureOffByDefault {
513 "kOff", base::FEATURE_DISABLED_BY_DEFAULT
514 };
515 struct base::Feature kFeatureOnByDefault {
516 "kOn", base::FEATURE_ENABLED_BY_DEFAULT
517 };
518 struct base::Feature kUnrelatedFeature {
519 "kUnrelated", base::FEATURE_DISABLED_BY_DEFAULT
520 };
521
522 struct {
523 const char* enable_feature;
524 const char* disable_feature;
525 bool expected_feature_off_state;
526 bool expected_feature_on_state;
527 } test_cases[] = {
528 {nullptr, nullptr, false, true},
529 {kFeatureOnByDefault.name, nullptr, false, true},
530 {kFeatureOffByDefault.name, nullptr, true, true},
531 {nullptr, kFeatureOnByDefault.name, false, false},
532 {nullptr, kFeatureOffByDefault.name, false, true},
533 };
534
535 for (size_t i = 0; i < arraysize(test_cases); i++) {
536 const auto& test_case = test_cases[i];
537 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
538
539 base::FieldTrialList field_trial_list(NULL);
540 base::FeatureList::ClearInstanceForTesting();
541 scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
542
543 Study study;
544 study.set_name("Study1");
545 study.set_default_experiment_name("B");
546 AddExperiment("B", 0, &study);
547
548 Study_Experiment* experiment = AddExperiment("A", 1, &study);
549 Study_Experiment_FeatureAssociation* association =
550 experiment->mutable_feature_association();
551 if (test_case.enable_feature)
552 association->add_enable_feature(test_case.enable_feature);
553 else if (test_case.disable_feature)
554 association->add_disable_feature(test_case.disable_feature);
555
556 EXPECT_TRUE(
557 CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
558 base::FeatureList::SetInstance(feature_list.Pass());
559
560 // |kUnrelatedFeature| should not be affected.
561 EXPECT_FALSE(base::FeatureList::IsEnabled(kUnrelatedFeature));
562
563 // Before the associated feature is queried, the trial shouldn't be active.
564 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(study.name()));
565
566 EXPECT_EQ(test_case.expected_feature_off_state,
567 base::FeatureList::IsEnabled(kFeatureOffByDefault));
568 EXPECT_EQ(test_case.expected_feature_on_state,
569 base::FeatureList::IsEnabled(kFeatureOnByDefault));
570
571 // The field trial should get activated if it had a feature association.
572 const bool expected_field_trial_active =
573 test_case.enable_feature || test_case.disable_feature;
574 EXPECT_EQ(expected_field_trial_active,
575 base::FieldTrialList::IsTrialActive(study.name()));
576 }
577 }
578
579 TEST_F(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
580 struct base::Feature kFeatureOffByDefault {
581 "kFeatureOffByDefault", base::FEATURE_DISABLED_BY_DEFAULT
582 };
583 struct base::Feature kFeatureOnByDefault {
584 "kFeatureOnByDefault", base::FEATURE_ENABLED_BY_DEFAULT
585 };
586
587 enum OneHundredPercentGroup {
588 DEFAULT_GROUP,
589 ENABLE_GROUP,
590 DISABLE_GROUP,
591 };
592
593 const char kDefaultGroup[] = "Default";
594 const char kEnabledGroup[] = "Enabled";
595 const char kDisabledGroup[] = "Disabled";
596 const char kForcedOnGroup[] = "ForcedOn";
597 const char kForcedOffGroup[] = "ForcedOff";
598
599 struct {
600 const base::Feature& feature;
601 const char* enable_features_command_line;
602 const char* disable_features_command_line;
603 OneHundredPercentGroup one_hundred_percent_group;
604
605 const char* expected_group;
606 bool expected_feature_state;
607 bool expected_trial_activated;
608 } test_cases[] = {
609 // Check what happens without and command-line forcing flags - that the
610 // |one_hundred_percent_group| gets correctly selected and does the right
611 // thing w.r.t. to affecting the feature / activating the trial.
612 {kFeatureOffByDefault, "", "", DEFAULT_GROUP, kDefaultGroup, false,
613 false},
614 {kFeatureOffByDefault, "", "", ENABLE_GROUP, kEnabledGroup, true, true},
615 {kFeatureOffByDefault, "", "", DISABLE_GROUP, kDisabledGroup, false,
616 true},
617
618 // Do the same as above, but for kFeatureOnByDefault feature.
619 {kFeatureOnByDefault, "", "", DEFAULT_GROUP, kDefaultGroup, true, false},
620 {kFeatureOnByDefault, "", "", ENABLE_GROUP, kEnabledGroup, true, true},
621 {kFeatureOnByDefault, "", "", DISABLE_GROUP, kDisabledGroup, false, true},
622
623 // Test forcing each feature on and off through the command-line and that
624 // the correct associated experiment gets chosen.
625 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", DEFAULT_GROUP,
626 kForcedOnGroup, true, true},
627 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, DEFAULT_GROUP,
628 kForcedOffGroup, false, true},
629 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", DEFAULT_GROUP,
630 kForcedOnGroup, true, true},
631 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, DEFAULT_GROUP,
632 kForcedOffGroup, false, true},
633
634 // Check that even if a feature should be enabled or disabled based on the
635 // the experiment probability weights, the forcing flag association still
636 // takes precedence. This is 4 cases as above, but with different values
637 // for |one_hundred_percent_group|.
638 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", ENABLE_GROUP,
639 kForcedOnGroup, true, true},
640 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, ENABLE_GROUP,
641 kForcedOffGroup, false, true},
642 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", ENABLE_GROUP,
643 kForcedOnGroup, true, true},
644 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, ENABLE_GROUP,
645 kForcedOffGroup, false, true},
646 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", DISABLE_GROUP,
647 kForcedOnGroup, true, true},
648 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, DISABLE_GROUP,
649 kForcedOffGroup, false, true},
650 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", DISABLE_GROUP,
651 kForcedOnGroup, true, true},
652 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, DISABLE_GROUP,
653 kForcedOffGroup, false, true},
654 };
655
656 for (size_t i = 0; i < arraysize(test_cases); i++) {
657 const auto& test_case = test_cases[i];
658 const int group = test_case.one_hundred_percent_group;
659 SCOPED_TRACE(base::StringPrintf(
660 "Test[%" PRIuS "]: %s [%s] [%s] %d", i, test_case.feature.name,
661 test_case.enable_features_command_line,
662 test_case.disable_features_command_line, static_cast<int>(group)));
663
664 base::FieldTrialList field_trial_list(NULL);
665 base::FeatureList::ClearInstanceForTesting();
666 scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
667 feature_list->InitializeFromCommandLine(
668 test_case.enable_features_command_line,
669 test_case.disable_features_command_line);
670
671 Study study;
672 study.set_name("Study1");
673 study.set_default_experiment_name("Default");
674 AddExperiment(kDefaultGroup, group == DEFAULT_GROUP ? 1 : 0, &study);
675
676 Study_Experiment* feature_enable =
677 AddExperiment(kEnabledGroup, group == ENABLE_GROUP ? 1 : 0, &study);
678 feature_enable->mutable_feature_association()->add_enable_feature(
679 test_case.feature.name);
680
681 Study_Experiment* feature_disable =
682 AddExperiment(kDisabledGroup, group == DISABLE_GROUP ? 1 : 0, &study);
683 feature_disable->mutable_feature_association()->add_disable_feature(
684 test_case.feature.name);
685
686 AddExperiment(kForcedOnGroup, 0, &study)
687 ->mutable_feature_association()
688 ->set_forcing_feature_on(test_case.feature.name);
689 AddExperiment(kForcedOffGroup, 0, &study)
690 ->mutable_feature_association()
691 ->set_forcing_feature_off(test_case.feature.name);
692
693 EXPECT_TRUE(
694 CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
695 base::FeatureList::SetInstance(feature_list.Pass());
696
697 // Trial should not be activated initially, but later might get activated
698 // depending on the expected values.
699 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(study.name()));
700 EXPECT_EQ(test_case.expected_feature_state,
701 base::FeatureList::IsEnabled(test_case.feature));
702 EXPECT_EQ(test_case.expected_trial_activated,
703 base::FieldTrialList::IsTrialActive(study.name()));
704 }
705 }
706
496 } // namespace variations 707 } // namespace variations
OLDNEW
« no previous file with comments | « components/variations/variations_seed_processor.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698