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

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: Address latest comments from isherman@. 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
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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 class VariationsSeedProcessorTest : public ::testing::Test { 112 class VariationsSeedProcessorTest : public ::testing::Test {
110 public: 113 public:
111 VariationsSeedProcessorTest() { 114 VariationsSeedProcessorTest() {
112 } 115 }
113 116
114 ~VariationsSeedProcessorTest() override { 117 ~VariationsSeedProcessorTest() override {
115 // Ensure that the maps are cleared between tests, since they are stored as 118 // Ensure that the maps are cleared between tests, since they are stored as
116 // process singletons. 119 // process singletons.
117 testing::ClearAllVariationIDs(); 120 testing::ClearAllVariationIDs();
118 testing::ClearAllVariationParams(); 121 testing::ClearAllVariationParams();
122
123 base::FeatureList::ClearInstanceForTesting();
119 } 124 }
120 125
121 bool CreateTrialFromStudy(const Study* study) { 126 bool CreateTrialFromStudy(const Study* study) {
127 return CreateTrialFromStudyWithFeatureList(study, &feature_list_);
128 }
129
130 bool CreateTrialFromStudyWithFeatureList(const Study* study,
131 base::FeatureList* feature_list) {
122 ProcessedStudy processed_study; 132 ProcessedStudy processed_study;
123 if (processed_study.Init(study, false)) { 133 if (processed_study.Init(study, false)) {
124 VariationsSeedProcessor().CreateTrialFromStudy( 134 VariationsSeedProcessor().CreateTrialFromStudy(
125 processed_study, override_callback_.callback()); 135 processed_study, override_callback_.callback(), feature_list);
126 return true; 136 return true;
127 } 137 }
128 return false; 138 return false;
129 } 139 }
130 140
131 protected: 141 protected:
142 base::FeatureList feature_list_;
132 TestOverrideStringCallback override_callback_; 143 TestOverrideStringCallback override_callback_;
133 144
134 private: 145 private:
135 DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessorTest); 146 DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessorTest);
136 }; 147 };
137 148
138 TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) { 149 TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) {
139 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1); 150 base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
140 151
141 base::FieldTrialList field_trial_list(NULL); 152 base::FieldTrialList field_trial_list(NULL);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 ASSERT_EQ(seed.study(0).name(), seed.study(1).name()); 230 ASSERT_EQ(seed.study(0).name(), seed.study(1).name());
220 231
221 const base::Time year_ago = 232 const base::Time year_ago =
222 base::Time::Now() - base::TimeDelta::FromDays(365); 233 base::Time::Now() - base::TimeDelta::FromDays(365);
223 234
224 const base::Version version("20.0.0.0"); 235 const base::Version version("20.0.0.0");
225 236
226 // Check that adding [expired, non-expired] activates the non-expired one. 237 // Check that adding [expired, non-expired] activates the non-expired one.
227 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName)); 238 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
228 { 239 {
240 base::FeatureList feature_list;
229 base::FieldTrialList field_trial_list(NULL); 241 base::FieldTrialList field_trial_list(NULL);
230 study1->set_expiry_date(TimeToProtoTime(year_ago)); 242 study1->set_expiry_date(TimeToProtoTime(year_ago));
231 seed_processor.CreateTrialsFromSeed( 243 seed_processor.CreateTrialsFromSeed(
232 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, 244 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
233 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback()); 245 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
246 &feature_list);
234 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); 247 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
235 } 248 }
236 249
237 // Check that adding [non-expired, expired] activates the non-expired one. 250 // Check that adding [non-expired, expired] activates the non-expired one.
238 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName)); 251 ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
239 { 252 {
253 base::FeatureList feature_list;
240 base::FieldTrialList field_trial_list(NULL); 254 base::FieldTrialList field_trial_list(NULL);
241 study1->clear_expiry_date(); 255 study1->clear_expiry_date();
242 study2->set_expiry_date(TimeToProtoTime(year_ago)); 256 study2->set_expiry_date(TimeToProtoTime(year_ago));
243 seed_processor.CreateTrialsFromSeed( 257 seed_processor.CreateTrialsFromSeed(
244 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, 258 seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
245 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback()); 259 Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
260 &feature_list);
246 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); 261 EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
247 } 262 }
248 } 263 }
249 264
250 TEST_F(VariationsSeedProcessorTest, OverrideUIStrings) { 265 TEST_F(VariationsSeedProcessorTest, OverrideUIStrings) {
251 base::FieldTrialList field_trial_list(NULL); 266 base::FieldTrialList field_trial_list(NULL);
252 267
253 Study study; 268 Study study;
254 study.set_name("Study1"); 269 study.set_name("Study1");
255 study.set_default_experiment_name("B"); 270 study.set_default_experiment_name("B");
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 study3->set_name("C"); 455 study3->set_name("C");
441 study3->set_default_experiment_name("Default"); 456 study3->set_default_experiment_name("Default");
442 AddExperiment("CC", 100, study3); 457 AddExperiment("CC", 100, study3);
443 AddExperiment("Default", 0, study3); 458 AddExperiment("Default", 0, study3);
444 study3->set_activation_type(Study_ActivationType_ACTIVATION_EXPLICIT); 459 study3->set_activation_type(Study_ActivationType_ACTIVATION_EXPLICIT);
445 460
446 VariationsSeedProcessor seed_processor; 461 VariationsSeedProcessor seed_processor;
447 seed_processor.CreateTrialsFromSeed( 462 seed_processor.CreateTrialsFromSeed(
448 seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"), 463 seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"),
449 Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", "", "", 464 Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", "", "",
450 override_callback_.callback()); 465 override_callback_.callback(), &feature_list_);
451 466
452 // Non-specified and ACTIVATION_EXPLICIT should not start active, but 467 // Non-specified and ACTIVATION_EXPLICIT should not start active, but
453 // ACTIVATION_AUTO should. 468 // ACTIVATION_AUTO should.
454 EXPECT_FALSE(IsFieldTrialActive("A")); 469 EXPECT_FALSE(IsFieldTrialActive("A"));
455 EXPECT_TRUE(IsFieldTrialActive("B")); 470 EXPECT_TRUE(IsFieldTrialActive("B"));
456 EXPECT_FALSE(IsFieldTrialActive("C")); 471 EXPECT_FALSE(IsFieldTrialActive("C"));
457 472
458 EXPECT_EQ("AA", base::FieldTrialList::FindFullName("A")); 473 EXPECT_EQ("AA", base::FieldTrialList::FindFullName("A"));
459 EXPECT_EQ("BB", base::FieldTrialList::FindFullName("B")); 474 EXPECT_EQ("BB", base::FieldTrialList::FindFullName("B"));
460 EXPECT_EQ("CC", base::FieldTrialList::FindFullName("C")); 475 EXPECT_EQ("CC", base::FieldTrialList::FindFullName("C"));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 EXPECT_EQ(kNonFlagGroupName, 512 EXPECT_EQ(kNonFlagGroupName,
498 base::FieldTrialList::FindFullName(study.name())); 513 base::FieldTrialList::FindFullName(study.name()));
499 514
500 // Check that params and experiment ids correspond. 515 // Check that params and experiment ids correspond.
501 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x")); 516 EXPECT_EQ("y", GetVariationParamValue(study.name(), "x"));
502 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName, 517 VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, kFlagStudyName,
503 kNonFlagGroupName); 518 kNonFlagGroupName);
504 EXPECT_EQ(kExperimentId, id); 519 EXPECT_EQ(kExperimentId, id);
505 } 520 }
506 521
522 TEST_F(VariationsSeedProcessorTest, FeatureEnabledOrDisableByTrial) {
523 struct base::Feature kFeatureOffByDefault {
524 "kOff", base::FEATURE_DISABLED_BY_DEFAULT
525 };
526 struct base::Feature kFeatureOnByDefault {
527 "kOn", base::FEATURE_ENABLED_BY_DEFAULT
528 };
529 struct base::Feature kUnrelatedFeature {
530 "kUnrelated", base::FEATURE_DISABLED_BY_DEFAULT
531 };
532
533 struct {
534 const char* enable_feature;
535 const char* disable_feature;
536 bool expected_feature_off_state;
537 bool expected_feature_on_state;
538 } test_cases[] = {
539 {nullptr, nullptr, false, true},
540 {kFeatureOnByDefault.name, nullptr, false, true},
541 {kFeatureOffByDefault.name, nullptr, true, true},
542 {nullptr, kFeatureOnByDefault.name, false, false},
543 {nullptr, kFeatureOffByDefault.name, false, true},
544 };
545
546 for (size_t i = 0; i < arraysize(test_cases); i++) {
547 const auto& test_case = test_cases[i];
548 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
549
550 base::FieldTrialList field_trial_list(NULL);
551 base::FeatureList::ClearInstanceForTesting();
552 scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
553
554 Study study;
555 study.set_name("Study1");
556 study.set_default_experiment_name("B");
557 AddExperiment("B", 0, &study);
558
559 Study_Experiment* experiment = AddExperiment("A", 1, &study);
560 Study_Experiment_FeatureAssociation* association =
561 experiment->mutable_feature_association();
562 if (test_case.enable_feature)
563 association->add_enable_feature(test_case.enable_feature);
564 else if (test_case.disable_feature)
565 association->add_disable_feature(test_case.disable_feature);
566
567 EXPECT_TRUE(
568 CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
569 base::FeatureList::SetInstance(feature_list.Pass());
570
571 // |kUnrelatedFeature| should not be affected.
572 EXPECT_FALSE(base::FeatureList::IsEnabled(kUnrelatedFeature));
573
574 // Before the associated feature is queried, the trial shouldn't be active.
575 EXPECT_FALSE(IsFieldTrialActive(study.name()));
576
577 EXPECT_EQ(test_case.expected_feature_off_state,
578 base::FeatureList::IsEnabled(kFeatureOffByDefault));
579 EXPECT_EQ(test_case.expected_feature_on_state,
580 base::FeatureList::IsEnabled(kFeatureOnByDefault));
581
582 // The field trial should get activated if it had a feature association.
583 const bool expected_field_trial_active =
584 test_case.enable_feature || test_case.disable_feature;
585 EXPECT_EQ(expected_field_trial_active, IsFieldTrialActive(study.name()));
586 }
587 }
588
589 TEST_F(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
590 struct base::Feature kFeatureOffByDefault {
591 "kFeatureOffByDefault", base::FEATURE_DISABLED_BY_DEFAULT
592 };
593 struct base::Feature kFeatureOnByDefault {
594 "kFeatureOnByDefault", base::FEATURE_ENABLED_BY_DEFAULT
595 };
596
597 enum OneHundredPercentGroup {
598 DEFAULT_GROUP,
599 ENABLE_GROUP,
600 DISABLE_GROUP,
601 };
602
603 const char kDefaultGroup[] = "Default";
604 const char kEnabledGroup[] = "Enabled";
605 const char kDisabledGroup[] = "Disabled";
606 const char kForcedOnGroup[] = "ForcedOn";
607 const char kForcedOffGroup[] = "ForcedOff";
608
609 struct {
610 const base::Feature& feature;
611 const char* enable_features_command_line;
612 const char* disable_features_command_line;
613 OneHundredPercentGroup one_hundred_percent_group;
614
615 const char* expected_group;
616 bool expected_feature_state;
617 bool expected_trial_activated;
618 } test_cases[] = {
619 // Check what happens without and command-line forcing flags - that the
620 // |one_hundred_percent_group| gets correctly selected and does the right
621 // thing w.r.t. to affecting the feature / activating the trial.
622 {kFeatureOffByDefault, "", "", DEFAULT_GROUP, kDefaultGroup, false,
623 false},
624 {kFeatureOffByDefault, "", "", ENABLE_GROUP, kEnabledGroup, true, true},
625 {kFeatureOffByDefault, "", "", DISABLE_GROUP, kDisabledGroup, false,
626 true},
627
628 // Do the same as above, but for kFeatureOnByDefault feature.
629 {kFeatureOnByDefault, "", "", DEFAULT_GROUP, kDefaultGroup, true, false},
630 {kFeatureOnByDefault, "", "", ENABLE_GROUP, kEnabledGroup, true, true},
631 {kFeatureOnByDefault, "", "", DISABLE_GROUP, kDisabledGroup, false, true},
632
633 // Test forcing each feature on and off through the command-line and that
634 // the correct associated experiment gets chosen.
635 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", DEFAULT_GROUP,
636 kForcedOnGroup, true, true},
637 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, DEFAULT_GROUP,
638 kForcedOffGroup, false, true},
639 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", DEFAULT_GROUP,
640 kForcedOnGroup, true, true},
641 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, DEFAULT_GROUP,
642 kForcedOffGroup, false, true},
643
644 // Check that even if a feature should be enabled or disabled based on the
645 // the experiment probability weights, the forcing flag association still
646 // takes precedence. This is 4 cases as above, but with different values
647 // for |one_hundred_percent_group|.
648 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", ENABLE_GROUP,
649 kForcedOnGroup, true, true},
650 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, ENABLE_GROUP,
651 kForcedOffGroup, false, true},
652 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", ENABLE_GROUP,
653 kForcedOnGroup, true, true},
654 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, ENABLE_GROUP,
655 kForcedOffGroup, false, true},
656 {kFeatureOffByDefault, kFeatureOffByDefault.name, "", DISABLE_GROUP,
657 kForcedOnGroup, true, true},
658 {kFeatureOffByDefault, "", kFeatureOffByDefault.name, DISABLE_GROUP,
659 kForcedOffGroup, false, true},
660 {kFeatureOnByDefault, kFeatureOnByDefault.name, "", DISABLE_GROUP,
661 kForcedOnGroup, true, true},
662 {kFeatureOnByDefault, "", kFeatureOnByDefault.name, DISABLE_GROUP,
663 kForcedOffGroup, false, true},
664 };
665
666 for (size_t i = 0; i < arraysize(test_cases); i++) {
667 const auto& test_case = test_cases[i];
668 const int group = test_case.one_hundred_percent_group;
669 SCOPED_TRACE(base::StringPrintf(
670 "Test[%" PRIuS "]: %s [%s] [%s] %d", i, test_case.feature.name,
671 test_case.enable_features_command_line,
672 test_case.disable_features_command_line, static_cast<int>(group)));
673
674 base::FieldTrialList field_trial_list(NULL);
675 base::FeatureList::ClearInstanceForTesting();
676 scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
677 feature_list->InitializeFromCommandLine(
678 test_case.enable_features_command_line,
679 test_case.disable_features_command_line);
680
681 Study study;
682 study.set_name("Study1");
683 study.set_default_experiment_name("Default");
684 AddExperiment(kDefaultGroup, group == DEFAULT_GROUP ? 1 : 0, &study);
685
686 Study_Experiment* feature_enable =
687 AddExperiment(kEnabledGroup, group == ENABLE_GROUP ? 1 : 0, &study);
688 feature_enable->mutable_feature_association()->add_enable_feature(
689 test_case.feature.name);
690
691 Study_Experiment* feature_disable =
692 AddExperiment(kDisabledGroup, group == DISABLE_GROUP ? 1 : 0, &study);
693 feature_disable->mutable_feature_association()->add_disable_feature(
694 test_case.feature.name);
695
696 AddExperiment(kForcedOnGroup, 0, &study)
697 ->mutable_feature_association()
698 ->set_forcing_feature_on(test_case.feature.name);
699 AddExperiment(kForcedOffGroup, 0, &study)
700 ->mutable_feature_association()
701 ->set_forcing_feature_off(test_case.feature.name);
702
703 EXPECT_TRUE(
704 CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
705 base::FeatureList::SetInstance(feature_list.Pass());
706
707 // Trial should not be activated initially, but later might get activated
708 // depending on the expected values.
709 EXPECT_FALSE(IsFieldTrialActive(study.name()));
710 EXPECT_EQ(test_case.expected_feature_state,
711 base::FeatureList::IsEnabled(test_case.feature));
712 EXPECT_EQ(test_case.expected_trial_activated,
713 IsFieldTrialActive(study.name()));
714 }
715 }
716
507 } // namespace variations 717 } // namespace variations
OLDNEW
« base/feature_list.cc ('K') | « components/variations/variations_seed_processor.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698