Added a SetForced method to allow forcing a new set of group bucketting.

This will be needed by the Finch client (soon to be known as the Variations Service) that will get updated information about FieldTrials and pre-feed the field trial list based on this information.

So this is different from CreateFieldTrial, which forced a group choice, this new method allows forcing a new set of appended groups.

BUG=121695
TEST=build\Debug\base_unittests.exe --gtest_filter=FieldTrialTest.SetForced


Review URL: https://chromiumcodereview.appspot.com/10382018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135748 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 0284bf7c813d9c57864048123abc7d456ee4f38a
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 245f2bf..6d4f2eb 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -170,6 +170,21 @@
   enable_benchmarking_ = true;
 }
 
+void FieldTrial::SetForced() {
+  // We might have been forced before (e.g., by CreateFieldTrial) and it's
+  // first come first served, e.g., command line switch has precedence.
+  if (forced_)
+    return;
+  // Explicit forcing should only be for cases where we want to set the group
+  // probabilities before the hard coded field trial setup is executed. So
+  // there must have been at least one non-default group appended at that point.
+  DCHECK_GT(next_group_number_, kDefaultGroupNumber + 1);
+
+  // And we must finalize the group choice before we mark ourselves as forced.
+  group();
+  forced_ = true;
+}
+
 FieldTrial::~FieldTrial() {}
 
 void FieldTrial::SetGroupChoice(const std::string& name, int number) {
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 87683a1..4807187 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -152,6 +152,16 @@
   // Enable benchmarking sets field trials to a common setting.
   static void EnableBenchmarking();
 
+  // Set the field trial as forced, meaning that it was setup earlier than
+  // the hard coded registration of the field trial to override it.
+  // This allows the code that was hard coded to register the field trial to
+  // still succeed even though the field trial has already been registered.
+  // This must be called after appending all the groups, since we will make
+  // the group choice here. Note that this is a NOOP for already forced trials.
+  // And, as the rest of the FieldTrial code, this is not thread safe and must
+  // be done from the UI thread.
+  void SetForced();
+
  private:
   // Allow tests to access our innards for testing purposes.
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 51e9aaa..f5c03c4 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -522,4 +522,36 @@
   EXPECT_NE(new_other_group, factory_trial->group());
 }
 
+TEST_F(FieldTrialTest, SetForced) {
+  // Start by setting a trial for which we ensure a winner...
+  int default_group_number = -1;
+  FieldTrial* forced_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &default_group_number);
+  EXPECT_EQ(forced_trial, forced_trial);
+
+  int forced_group = forced_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, forced_trial->group());
+
+  // Now force it.
+  forced_trial->SetForced();
+
+  // Now try to set it up differently as a hard coded registration would.
+  FieldTrial* hard_coded_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &default_group_number);
+  EXPECT_EQ(hard_coded_trial, forced_trial);
+
+  int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
+  EXPECT_EQ(forced_group, hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_lose_group);
+
+  // Same thing if we would have done it to win again.
+  FieldTrial* other_hard_coded_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &default_group_number);
+  EXPECT_EQ(other_hard_coded_trial, forced_trial);
+
+  int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, other_hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_win_group);
+}
+
 }  // namespace base