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

Unified 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 Rob's comments. Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: components/variations/variations_seed_processor_unittest.cc
diff --git a/components/variations/variations_seed_processor_unittest.cc b/components/variations/variations_seed_processor_unittest.cc
index 437c611fb39878a917a3879dea2189df7b38e69a..dad2406da307bb74a607d344882ba9562fbec035 100644
--- a/components/variations/variations_seed_processor_unittest.cc
+++ b/components/variations/variations_seed_processor_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "components/variations/processed_study.h"
@@ -119,16 +120,22 @@ class VariationsSeedProcessorTest : public ::testing::Test {
}
bool CreateTrialFromStudy(const Study* study) {
+ return CreateTrialFromStudyWithFeatureList(study, &feature_list_);
+ }
+
+ bool CreateTrialFromStudyWithFeatureList(const Study* study,
+ base::FeatureList* feature_list) {
ProcessedStudy processed_study;
if (processed_study.Init(study, false)) {
VariationsSeedProcessor().CreateTrialFromStudy(
- processed_study, override_callback_.callback());
+ processed_study, override_callback_.callback(), feature_list);
return true;
}
return false;
}
protected:
+ base::FeatureList feature_list_;
TestOverrideStringCallback override_callback_;
private:
@@ -226,23 +233,27 @@ TEST_F(VariationsSeedProcessorTest,
// Check that adding [expired, non-expired] activates the non-expired one.
ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
{
+ base::FeatureList feature_list;
base::FieldTrialList field_trial_list(NULL);
study1->set_expiry_date(TimeToProtoTime(year_ago));
seed_processor.CreateTrialsFromSeed(
seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
- Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback());
+ Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
+ &feature_list);
EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
}
// Check that adding [non-expired, expired] activates the non-expired one.
ASSERT_EQ(std::string(), base::FieldTrialList::FindFullName(kTrialName));
{
+ base::FeatureList feature_list;
base::FieldTrialList field_trial_list(NULL);
study1->clear_expiry_date();
study2->set_expiry_date(TimeToProtoTime(year_ago));
seed_processor.CreateTrialsFromSeed(
seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE,
- Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback());
+ Study_FormFactor_DESKTOP, "", "", "", override_callback_.callback(),
+ &feature_list);
EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
}
}
@@ -447,7 +458,7 @@ TEST_F(VariationsSeedProcessorTest, StartsActive) {
seed_processor.CreateTrialsFromSeed(
seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"),
Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", "", "",
- override_callback_.callback());
+ override_callback_.callback(), &feature_list_);
// Non-specified and ACTIVATION_EXPLICIT should not start active, but
// ACTIVATION_AUTO should.
@@ -504,4 +515,151 @@ TEST_F(VariationsSeedProcessorTest, ForcingFlagAlreadyForced) {
EXPECT_EQ(kExperimentId, id);
}
+TEST_F(VariationsSeedProcessorTest, FeatureEnabledOrDisableByTrial) {
+ struct base::Feature kFeatureOffByDefault {
+ "kOff", base::FEATURE_DISABLED_BY_DEFAULT
+ };
+ struct base::Feature kFeatureOnByDefault {
+ "kOn", base::FEATURE_ENABLED_BY_DEFAULT
+ };
+ struct base::Feature kUnrelatedFeature {
+ "kUnrelated", base::FEATURE_DISABLED_BY_DEFAULT
+ };
+
+ struct {
+ const char* enable_feature;
+ const char* disable_feature;
+ bool expected_feature_off_state;
+ bool expected_feature_on_state;
+ } test_cases[] = {
+ {nullptr, nullptr, false, true},
+ {kFeatureOnByDefault.name, nullptr, false, true},
+ {kFeatureOffByDefault.name, nullptr, true, true},
+ {nullptr, kFeatureOnByDefault.name, false, false},
+ {nullptr, kFeatureOffByDefault.name, false, true},
+ };
+
+ for (size_t i = 0; i < arraysize(test_cases); i++) {
+ const auto& test_case = test_cases[i];
+
+ base::FieldTrialList field_trial_list(NULL);
+ base::FeatureList::ClearInstanceForTesting();
Ilya Sherman 2015/09/16 00:50:44 Should this also be called at the end of each test
Alexei Svitkine (slow) 2015/09/22 21:19:59 Good point. Put in the dtor of the harness.
+ scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+
+ Study study;
+ study.set_name("Study1");
+ study.set_default_experiment_name("B");
+ AddExperiment("B", 0, &study);
+
+ Study_Experiment* experiment = AddExperiment("A", 1, &study);
+ Study_Experiment_FeatureAssociation* association =
+ experiment->mutable_feature_association();
+ if (test_case.enable_feature)
+ association->add_enable_feature(test_case.enable_feature);
+ else if (test_case.disable_feature)
+ association->add_disable_feature(test_case.disable_feature);
+
+ EXPECT_TRUE(
+ CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
+ base::FeatureList::SetInstance(feature_list.Pass());
+
+ // |kUnrelatedFeature| should not be affected.
+ EXPECT_FALSE(base::FeatureList::IsEnabled(kUnrelatedFeature));
+
+ // Before the associated feature is queried, the trial shouldn't be active.
+ EXPECT_FALSE(IsFieldTrialActive(study.name()));
+
+ EXPECT_EQ(test_case.expected_feature_off_state,
+ base::FeatureList::IsEnabled(kFeatureOffByDefault));
+ EXPECT_EQ(test_case.expected_feature_on_state,
+ base::FeatureList::IsEnabled(kFeatureOnByDefault));
+
+ // The field trial should get activated if it had a feature association.
+ const bool expected_field_trial_active =
+ test_case.enable_feature || test_case.disable_feature;
+ EXPECT_EQ(expected_field_trial_active, IsFieldTrialActive(study.name()));
+ }
+}
+
+TEST_F(VariationsSeedProcessorTest, FeatureForcingTrialReportingGroup) {
+ struct base::Feature kFeatureOffByDefault {
+ "kOff", base::FEATURE_DISABLED_BY_DEFAULT
+ };
+ struct base::Feature kFeatureOnByDefault {
+ "kOn", base::FEATURE_ENABLED_BY_DEFAULT
+ };
+
+ struct {
+ const base::Feature& feature;
+ bool set_forcing_feature_on;
+ bool set_forcing_feature_off;
+ const char* enable_features_command_line;
+ const char* disable_features_command_line;
+ bool expected_feature_state;
+ bool expected_trial_activated;
+ } test_cases[] = {
+ {kFeatureOffByDefault, false, false, "", "", false, false},
+ {kFeatureOffByDefault, true, false, kFeatureOffByDefault.name, "", true,
+ true},
+ {kFeatureOffByDefault, false, true, kFeatureOffByDefault.name, "", true,
+ false},
+ {kFeatureOffByDefault, false, true, "", kFeatureOffByDefault.name, false,
+ true},
+ {kFeatureOffByDefault, true, false, "", kFeatureOffByDefault.name, false,
+ false},
+ {kFeatureOnByDefault, false, false, "", "", true, false},
+ {kFeatureOnByDefault, true, false, kFeatureOnByDefault.name, "", true,
+ true},
+ {kFeatureOnByDefault, false, true, kFeatureOnByDefault.name, "", true,
+ false},
+ {kFeatureOnByDefault, false, true, "", kFeatureOnByDefault.name, false,
+ true},
+ {kFeatureOnByDefault, true, false, "", kFeatureOnByDefault.name, false,
+ false},
+ };
Ilya Sherman 2015/09/16 00:50:44 This test is pretty dense, making it hard to read.
Alexei Svitkine (slow) 2015/09/22 21:19:59 Let me think about. I started it as individual tes
Alexei Svitkine (slow) 2015/09/23 22:01:27 Thinking about this more, I agree that this test i
Ilya Sherman 2015/09/24 01:11:32 The comments help a bunch -- thanks! I think my m
Alexei Svitkine (slow) 2015/09/24 20:49:21 I agree that complicated table-driven tests are ha
+
+ for (size_t i = 0; i < arraysize(test_cases); i++) {
+ const auto& test_case = test_cases[i];
+
+ base::FieldTrialList field_trial_list(NULL);
+ base::FeatureList::ClearInstanceForTesting();
+ scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(
+ test_case.enable_features_command_line,
+ test_case.disable_features_command_line);
+
+ Study study;
+ study.set_name("Study1");
+ study.set_default_experiment_name("B");
+ Study_Experiment* experiment_with_probability =
+ AddExperiment("B", 1, &study);
+
+ Study_Experiment* experiment = AddExperiment("A", 0, &study);
+ Study_Experiment_FeatureAssociation* association =
+ experiment->mutable_feature_association();
+ if (test_case.set_forcing_feature_on)
+ association->set_forcing_feature_on(test_case.feature.name);
+ else if (test_case.set_forcing_feature_off)
+ association->set_forcing_feature_off(test_case.feature.name);
+
+ EXPECT_TRUE(
+ CreateTrialFromStudyWithFeatureList(&study, feature_list.get()));
+ base::FeatureList::SetInstance(feature_list.Pass());
+
+ // Trial should not be activated initially.
+ EXPECT_FALSE(IsFieldTrialActive(study.name()));
+ EXPECT_EQ(test_case.expected_feature_state,
+ base::FeatureList::IsEnabled(test_case.feature));
+ EXPECT_EQ(test_case.expected_trial_activated,
+ IsFieldTrialActive(study.name()));
+ if (test_case.expected_trial_activated) {
+ EXPECT_EQ(experiment->name(),
+ base::FieldTrialList::FindFullName(study.name()));
+ } else {
+ EXPECT_EQ(experiment_with_probability->name(),
+ base::FieldTrialList::FindFullName(study.name()));
+ }
+ }
+}
Ilya Sherman 2015/09/16 00:50:44 It would be nice to add tests for what happens in
Alexei Svitkine (slow) 2015/09/16 20:54:08 This is meant to be enforced server-side. I guess
Ilya Sherman 2015/09/17 01:02:46 I guess for things that are strictly enforced serv
+
} // namespace variations

Powered by Google App Engine
This is Rietveld 408576698