summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-05 18:24:40 +0000
committerasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-05 18:24:40 +0000
commit7e797793d31525002837e3a078be62a7c9e94c4e (patch)
tree2b4315fc721b36cd97306af4cd76720d9ce70cdd
parent37fad6b194217278d700f40fd6ea2b09d6a86535 (diff)
downloadchromium_src-7e797793d31525002837e3a078be62a7c9e94c4e.zip
chromium_src-7e797793d31525002837e3a078be62a7c9e94c4e.tar.gz
chromium_src-7e797793d31525002837e3a078be62a7c9e94c4e.tar.bz2
Split variations_util.cc into two separate files.
Moves id and param association to variations_associated_data.cc, while keeping the rest of the functionality in variations_util.cc. No functional changes. BUG=266007 TEST=Existing unit tests. Review URL: https://chromiumcodereview.appspot.com/21401002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215644 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/metrics/variations/variations_http_header_provider.cc2
-rw-r--r--chrome/browser/metrics/variations/variations_seed_processor.cc2
-rw-r--r--chrome/browser/ui/bookmarks/bookmark_prompt_controller.cc2
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/common/metrics/variations/variations_associated_data.cc227
-rw-r--r--chrome/common/metrics/variations/variations_associated_data.h151
-rw-r--r--chrome/common/metrics/variations/variations_associated_data_unittest.cc307
-rw-r--r--chrome/common/metrics/variations/variations_util.cc220
-rw-r--r--chrome/common/metrics/variations/variations_util.h124
-rw-r--r--chrome/common/metrics/variations/variations_util_unittest.cc287
11 files changed, 710 insertions, 615 deletions
diff --git a/chrome/browser/metrics/variations/variations_http_header_provider.cc b/chrome/browser/metrics/variations/variations_http_header_provider.cc
index 8142240..f4ed100 100644
--- a/chrome/browser/metrics/variations/variations_http_header_provider.cc
+++ b/chrome/browser/metrics/variations/variations_http_header_provider.cc
@@ -10,7 +10,7 @@
#include "base/strings/string_util.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/common/metrics/proto/chrome_experiments.pb.h"
-#include "chrome/common/metrics/variations/variations_util.h"
+#include "chrome/common/metrics/variations/variations_associated_data.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/http/http_request_headers.h"
#include "url/gurl.h"
diff --git a/chrome/browser/metrics/variations/variations_seed_processor.cc b/chrome/browser/metrics/variations/variations_seed_processor.cc
index ef98d85..13f34f9 100644
--- a/chrome/browser/metrics/variations/variations_seed_processor.cc
+++ b/chrome/browser/metrics/variations/variations_seed_processor.cc
@@ -12,7 +12,7 @@
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/proto/trials_seed.pb.h"
-#include "chrome/common/metrics/variations/variations_util.h"
+#include "chrome/common/metrics/variations/variations_associated_data.h"
namespace chrome_variations {
diff --git a/chrome/browser/ui/bookmarks/bookmark_prompt_controller.cc b/chrome/browser/ui/bookmarks/bookmark_prompt_controller.cc
index 6013a1b..386669d 100644
--- a/chrome/browser/ui/bookmarks/bookmark_prompt_controller.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_prompt_controller.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/metrics/variations/variation_ids.h"
-#include "chrome/common/metrics/variations/variations_util.h"
+#include "chrome/common/metrics/variations/variations_associated_data.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 4647180..d510065 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -400,6 +400,8 @@
'common/metrics/metrics_util.h',
'common/metrics/variations/uniformity_field_trials.cc',
'common/metrics/variations/uniformity_field_trials.h',
+ 'common/metrics/variations/variations_associated_data.cc',
+ 'common/metrics/variations/variations_associated_data.h',
'common/metrics/variations/variations_util.cc',
'common/metrics/variations/variations_util.h',
'common/multi_process_lock.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 6e8a5fa..b7e3d06 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1741,6 +1741,7 @@
'common/metrics/metrics_log_base_unittest.cc',
'common/metrics/metrics_log_manager_unittest.cc',
'common/metrics/metrics_util_unittest.cc',
+ 'common/metrics/variations/variations_associated_data_unittest.cc',
'common/metrics/variations/variations_util_unittest.cc',
'common/multi_process_lock_unittest.cc',
'common/net/url_fixer_upper_unittest.cc',
diff --git a/chrome/common/metrics/variations/variations_associated_data.cc b/chrome/common/metrics/variations/variations_associated_data.cc
new file mode 100644
index 0000000..f74bc85
--- /dev/null
+++ b/chrome/common/metrics/variations/variations_associated_data.cc
@@ -0,0 +1,227 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/metrics/variations/variations_associated_data.h"
+
+#include <map>
+#include <vector>
+
+#include "base/memory/singleton.h"
+#include "chrome/common/metrics/metrics_util.h"
+#include "chrome/common/metrics/variations/variation_ids.h"
+
+namespace chrome_variations {
+
+namespace {
+
+// The internal singleton accessor for the map, used to keep it thread-safe.
+class GroupMapAccessor {
+ public:
+ typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
+ GroupToIDMap;
+
+ // Retrieve the singleton.
+ static GroupMapAccessor* GetInstance() {
+ return Singleton<GroupMapAccessor>::get();
+ }
+
+ // Note that this normally only sets the ID for a group the first time, unless
+ // |force| is set to true, in which case it will always override it.
+ void AssociateID(IDCollectionKey key,
+ const ActiveGroupId& group_identifier,
+ const VariationID id,
+ const bool force) {
+#if !defined(NDEBUG)
+ // Validate that all collections with this |group_identifier| have the same
+ // associated ID.
+ DCHECK_EQ(2, ID_COLLECTION_COUNT);
+ IDCollectionKey other_key = GOOGLE_WEB_PROPERTIES;
+ if (key == GOOGLE_WEB_PROPERTIES)
+ other_key = GOOGLE_UPDATE_SERVICE;
+ VariationID other_id = GetID(other_key, group_identifier);
+ DCHECK(other_id == EMPTY_ID || other_id == id);
+#endif
+
+ base::AutoLock scoped_lock(lock_);
+
+ GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
+ if (force ||
+ group_to_id_map->find(group_identifier) == group_to_id_map->end())
+ (*group_to_id_map)[group_identifier] = id;
+ }
+
+ VariationID GetID(IDCollectionKey key,
+ const ActiveGroupId& group_identifier) {
+ base::AutoLock scoped_lock(lock_);
+ GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
+ GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier);
+ if (it == group_to_id_map->end())
+ return EMPTY_ID;
+ return it->second;
+ }
+
+ void ClearAllMapsForTesting() {
+ base::AutoLock scoped_lock(lock_);
+
+ for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
+ GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i));
+ DCHECK(map);
+ map->clear();
+ }
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<GroupMapAccessor>;
+
+ // Retrieves the GroupToIDMap for |key|.
+ GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
+ return &group_to_id_maps_[key];
+ }
+
+ GroupMapAccessor() {
+ group_to_id_maps_.resize(ID_COLLECTION_COUNT);
+ }
+ ~GroupMapAccessor() {}
+
+ base::Lock lock_;
+ std::vector<GroupToIDMap> group_to_id_maps_;
+
+ DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor);
+};
+
+// Singleton helper class that keeps track of the parameters of all variations
+// and ensures access to these is thread-safe.
+class VariationsParamAssociator {
+ public:
+ typedef std::pair<std::string, std::string> VariationKey;
+ typedef std::map<std::string, std::string> VariationParams;
+
+ // Retrieve the singleton.
+ static VariationsParamAssociator* GetInstance() {
+ return Singleton<VariationsParamAssociator>::get();
+ }
+
+ bool AssociateVariationParams(const std::string& trial_name,
+ const std::string& group_name,
+ const VariationParams& params) {
+ base::AutoLock scoped_lock(lock_);
+
+ if (IsFieldTrialActive(trial_name))
+ return false;
+
+ const VariationKey key(trial_name, group_name);
+ if (ContainsKey(variation_params_, key))
+ return false;
+
+ variation_params_[key] = params;
+ return true;
+ }
+
+ bool GetVariationParams(const std::string& trial_name,
+ VariationParams* params) {
+ base::AutoLock scoped_lock(lock_);
+
+ const std::string group_name =
+ base::FieldTrialList::FindFullName(trial_name);
+ const VariationKey key(trial_name, group_name);
+ if (!ContainsKey(variation_params_, key))
+ return false;
+
+ *params = variation_params_[key];
+ return true;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<VariationsParamAssociator>;
+
+ VariationsParamAssociator() {}
+ ~VariationsParamAssociator() {}
+
+ // Tests whether a field trial is active (i.e. group() has been called on it).
+ // TODO(asvitkine): Expose this as an API on base::FieldTrial.
+ bool IsFieldTrialActive(const std::string& trial_name) {
+ base::FieldTrial::ActiveGroups active_groups;
+ base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+ for (size_t i = 0; i < active_groups.size(); ++i) {
+ if (active_groups[i].trial_name == trial_name)
+ return true;
+ }
+ return false;
+ }
+
+ base::Lock lock_;
+ std::map<VariationKey, VariationParams> variation_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
+};
+
+} // namespace
+
+ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
+ const std::string& group_name) {
+ ActiveGroupId id;
+ id.name = metrics::HashName(trial_name);
+ id.group = metrics::HashName(group_name);
+ return id;
+}
+
+void AssociateGoogleVariationID(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name,
+ VariationID id) {
+ GroupMapAccessor::GetInstance()->AssociateID(
+ key, MakeActiveGroupId(trial_name, group_name), id, false);
+}
+
+void AssociateGoogleVariationIDForce(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name,
+ VariationID id) {
+ GroupMapAccessor::GetInstance()->AssociateID(
+ key, MakeActiveGroupId(trial_name, group_name), id, true);
+}
+
+VariationID GetGoogleVariationID(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name) {
+ return GroupMapAccessor::GetInstance()->GetID(
+ key, MakeActiveGroupId(trial_name, group_name));
+}
+
+bool AssociateVariationParams(
+ const std::string& trial_name,
+ const std::string& group_name,
+ const std::map<std::string, std::string>& params) {
+ return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
+ trial_name, group_name, params);
+}
+
+bool GetVariationParams(const std::string& trial_name,
+ std::map<std::string, std::string>* params) {
+ return VariationsParamAssociator::GetInstance()->GetVariationParams(
+ trial_name, params);
+}
+
+std::string GetVariationParamValue(const std::string& trial_name,
+ const std::string& param_name) {
+ std::map<std::string, std::string> params;
+ if (GetVariationParams(trial_name, &params)) {
+ std::map<std::string, std::string>::iterator it = params.find(param_name);
+ if (it != params.end())
+ return it->second;
+ }
+ return std::string();
+}
+
+// Functions below are exposed for testing explicitly behind this namespace.
+// They simply wrap existing functions in this file.
+namespace testing {
+
+void ClearAllVariationIDs() {
+ GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
+}
+
+} // namespace testing
+
+} // namespace chrome_variations
diff --git a/chrome/common/metrics/variations/variations_associated_data.h b/chrome/common/metrics/variations/variations_associated_data.h
new file mode 100644
index 0000000..182b66b
--- /dev/null
+++ b/chrome/common/metrics/variations/variations_associated_data.h
@@ -0,0 +1,151 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
+#define CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
+
+#include <map>
+#include <string>
+
+#include "base/metrics/field_trial.h"
+#include "base/strings/string16.h"
+#include "chrome/common/metrics/variations/variation_ids.h"
+
+// This file provides various helpers that extend the functionality around
+// base::FieldTrial.
+//
+// This includes several simple APIs to handle getting and setting additional
+// data related to Chrome variations, such as parameters and Google variation
+// IDs. These APIs are meant to extend the base::FieldTrial APIs to offer extra
+// functionality that is not offered by the simpler base::FieldTrial APIs.
+//
+// The AssociateGoogleVariationID and AssociateVariationParams functions are
+// generally meant to be called by the VariationsService based on server-side
+// variation configs, but may also be used for client-only field trials by
+// invoking them directly after appending all the groups to a FieldTrial.
+//
+// Experiment code can then use the getter APIs to retrieve variation parameters
+// or IDs:
+//
+// std::map<std::string, std::string> params;
+// if (GetVariationParams("trial", &params)) {
+// // use |params|
+// }
+//
+// std::string value = GetVariationParamValue("trial", "param_x");
+// // use |value|, which will be "" if it does not exist
+//
+// VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial",
+// "group1");
+// if (id != chrome_variations::kEmptyID) {
+// // use |id|
+// }
+
+namespace chrome_variations {
+
+// The Unique ID of a trial and its active group, where the name and group
+// identifiers are hashes of the trial and group name strings.
+struct ActiveGroupId {
+ uint32 name;
+ uint32 group;
+};
+
+// Returns an ActiveGroupId struct for the given trial and group names.
+ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
+ const std::string& group_name);
+
+// We need to supply a Compare class for templates since ActiveGroupId is a
+// user-defined type.
+struct ActiveGroupIdCompare {
+ bool operator() (const ActiveGroupId& lhs, const ActiveGroupId& rhs) const {
+ // The group and name fields are just SHA-1 Hashes, so we just need to treat
+ // them as IDs and do a less-than comparison. We test group first, since
+ // name is more likely to collide.
+ if (lhs.group != rhs.group)
+ return lhs.group < rhs.group;
+ return lhs.name < rhs.name;
+ }
+};
+
+// A key into the Associate/Get methods for VariationIDs. This is used to create
+// separate ID associations for separate parties interested in VariationIDs.
+enum IDCollectionKey {
+ // This collection is used by Google web properties, transmitted through the
+ // X-Chrome-Variations header.
+ GOOGLE_WEB_PROPERTIES,
+ // This collection is used by Google update services, transmitted through the
+ // Google Update experiment labels.
+ GOOGLE_UPDATE_SERVICE,
+ // The total count of collections.
+ ID_COLLECTION_COUNT,
+};
+
+// Associate a chrome_variations::VariationID value with a FieldTrial group for
+// collection |key|. If an id was previously set for |trial_name| and
+// |group_name|, this does nothing. The group is denoted by |trial_name| and
+// |group_name|. This must be called whenever a FieldTrial is prepared (create
+// the trial and append groups) and needs to have a
+// chrome_variations::VariationID associated with it so Google servers can
+// recognize the FieldTrial. Thread safe.
+void AssociateGoogleVariationID(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name,
+ VariationID id);
+
+// As above, but overwrites any previously set id. Thread safe.
+void AssociateGoogleVariationIDForce(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name,
+ VariationID id);
+
+// Retrieve the chrome_variations::VariationID associated with a FieldTrial
+// group for collection |key|. The group is denoted by |trial_name| and
+// |group_name|. This will return chrome_variations::kEmptyID if there is
+// currently no associated ID for the named group. This API can be nicely
+// combined with FieldTrial::GetActiveFieldTrialGroups() to enumerate the
+// variation IDs for all active FieldTrial groups. Thread safe.
+VariationID GetGoogleVariationID(IDCollectionKey key,
+ const std::string& trial_name,
+ const std::string& group_name);
+
+// Associates the specified set of key-value |params| with the variation
+// specified by |trial_name| and |group_name|. Fails and returns false if the
+// specified variation already has params associated with it or the field trial
+// is already active (group() has been called on it). Thread safe.
+bool AssociateVariationParams(const std::string& trial_name,
+ const std::string& group_name,
+ const std::map<std::string, std::string>& params);
+
+// Retrieves the set of key-value |params| for the variation associated with
+// the specified field trial, based on its selected group. If the field trial
+// does not exist or its selected group does not have any parameters associated
+// with it, returns false and does not modify |params|. Calling this function
+// will result in the field trial being marked as active if found (i.e. group()
+// will be called on it), if it wasn't already. Currently, this information is
+// only available from the browser process. Thread safe.
+bool GetVariationParams(const std::string& trial_name,
+ std::map<std::string, std::string>* params);
+
+// Retrieves a specific parameter value corresponding to |param_name| for the
+// variation associated with the specified field trial, based on its selected
+// group. If the field trial does not exist or the specified parameter does not
+// exist, returns an empty string. Calling this function will result in the
+// field trial being marked as active if found (i.e. group() will be called on
+// it), if it wasn't already. Currently, this information is only available from
+// the browser process. Thread safe.
+std::string GetVariationParamValue(const std::string& trial_name,
+ const std::string& param_name);
+
+// Expose some functions for testing. These functions just wrap functionality
+// that is implemented above.
+namespace testing {
+
+// Clears all of the mapped associations.
+void ClearAllVariationIDs();
+
+} // namespace testing
+
+} // namespace chrome_variations
+
+#endif // CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
diff --git a/chrome/common/metrics/variations/variations_associated_data_unittest.cc b/chrome/common/metrics/variations/variations_associated_data_unittest.cc
new file mode 100644
index 0000000..2a194af
--- /dev/null
+++ b/chrome/common/metrics/variations/variations_associated_data_unittest.cc
@@ -0,0 +1,307 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/metrics/variations/variations_associated_data.h"
+
+#include "base/metrics/field_trial.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_variations {
+
+namespace {
+
+// Convenience helper to retrieve the chrome_variations::VariationID for a
+// FieldTrial. Note that this will do the group assignment in |trial| if not
+// already done.
+VariationID GetIDForTrial(IDCollectionKey key, base::FieldTrial* trial) {
+ return GetGoogleVariationID(key, trial->trial_name(), trial->group_name());
+}
+
+// Tests whether a field trial is active (i.e. group() has been called on it).
+bool IsFieldTrialActive(const std::string& trial_name) {
+ base::FieldTrial::ActiveGroups active_groups;
+ base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+ for (size_t i = 0; i < active_groups.size(); ++i) {
+ if (active_groups[i].trial_name == trial_name)
+ return true;
+ }
+ return false;
+}
+
+// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
+scoped_refptr<base::FieldTrial> CreateFieldTrial(
+ const std::string& trial_name,
+ int total_probability,
+ const std::string& default_group_name,
+ int* default_group_number) {
+ return base::FieldTrialList::FactoryGetFieldTrial(
+ trial_name, total_probability, default_group_name,
+ base::FieldTrialList::kNoExpirationYear, 1, 1,
+ base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
+}
+
+} // namespace
+
+class VariationsAssociatedDataTest : public ::testing::Test {
+ public:
+ VariationsAssociatedDataTest() : field_trial_list_(NULL) {
+ }
+
+ virtual ~VariationsAssociatedDataTest() {
+ // Ensure that the maps are cleared between tests, since they are stored as
+ // process singletons.
+ testing::ClearAllVariationIDs();
+ }
+
+ private:
+ base::FieldTrialList field_trial_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(VariationsAssociatedDataTest);
+};
+
+// Test that if the trial is immediately disabled, GetGoogleVariationID just
+// returns the empty ID.
+TEST_F(VariationsAssociatedDataTest, DisableImmediately) {
+ int default_group_number = -1;
+ scoped_refptr<base::FieldTrial> trial(
+ CreateFieldTrial("trial", 100, "default", &default_group_number));
+
+ ASSERT_EQ(default_group_number, trial->group());
+ ASSERT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
+}
+
+// Test that successfully associating the FieldTrial with some ID, and then
+// disabling the FieldTrial actually makes GetGoogleVariationID correctly
+// return the empty ID.
+TEST_F(VariationsAssociatedDataTest, DisableAfterInitialization) {
+ const std::string default_name = "default";
+ const std::string non_default_name = "non_default";
+
+ scoped_refptr<base::FieldTrial> trial(
+ CreateFieldTrial("trial", 100, default_name, NULL));
+
+ trial->AppendGroup(non_default_name, 100);
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
+ default_name, TEST_VALUE_A);
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
+ non_default_name, TEST_VALUE_B);
+ trial->Disable();
+ ASSERT_EQ(default_name, trial->group_name());
+ ASSERT_EQ(TEST_VALUE_A, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
+}
+
+// Test various successful association cases.
+TEST_F(VariationsAssociatedDataTest, AssociateGoogleVariationID) {
+ const std::string default_name1 = "default";
+ scoped_refptr<base::FieldTrial> trial_true(
+ CreateFieldTrial("d1", 10, default_name1, NULL));
+ const std::string winner = "TheWinner";
+ int winner_group = trial_true->AppendGroup(winner, 10);
+
+ // Set GoogleVariationIDs so we can verify that they were chosen correctly.
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
+ default_name1, TEST_VALUE_A);
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
+ winner, TEST_VALUE_B);
+
+ EXPECT_EQ(winner_group, trial_true->group());
+ EXPECT_EQ(winner, trial_true->group_name());
+ EXPECT_EQ(TEST_VALUE_B,
+ GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
+
+ const std::string default_name2 = "default2";
+ scoped_refptr<base::FieldTrial> trial_false(
+ CreateFieldTrial("d2", 10, default_name2, NULL));
+ const std::string loser = "ALoser";
+ const int loser_group = trial_false->AppendGroup(loser, 0);
+
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
+ default_name2, TEST_VALUE_A);
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
+ loser, TEST_VALUE_B);
+
+ EXPECT_NE(loser_group, trial_false->group());
+ EXPECT_EQ(TEST_VALUE_A,
+ GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_false.get()));
+}
+
+// Test that not associating a FieldTrial with any IDs ensure that the empty ID
+// will be returned.
+TEST_F(VariationsAssociatedDataTest, NoAssociation) {
+ const std::string default_name = "default";
+ scoped_refptr<base::FieldTrial> no_id_trial(
+ CreateFieldTrial("d3", 10, default_name, NULL));
+
+ const std::string winner = "TheWinner";
+ const int winner_group = no_id_trial->AppendGroup(winner, 10);
+
+ // Ensure that despite the fact that a normal winner is elected, it does not
+ // have a valid VariationID associated with it.
+ EXPECT_EQ(winner_group, no_id_trial->group());
+ EXPECT_EQ(winner, no_id_trial->group_name());
+ EXPECT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, no_id_trial.get()));
+}
+
+// Ensure that the AssociateGoogleVariationIDForce works as expected.
+TEST_F(VariationsAssociatedDataTest, ForceAssociation) {
+ EXPECT_EQ(EMPTY_ID,
+ GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
+ TEST_VALUE_A);
+ EXPECT_EQ(TEST_VALUE_A,
+ GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
+ TEST_VALUE_B);
+ EXPECT_EQ(TEST_VALUE_A,
+ GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
+ AssociateGoogleVariationIDForce(GOOGLE_WEB_PROPERTIES, "trial", "group",
+ TEST_VALUE_B);
+ EXPECT_EQ(TEST_VALUE_B,
+ GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
+}
+
+// Ensure that two collections can coexist without affecting each other.
+TEST_F(VariationsAssociatedDataTest, CollectionsCoexist) {
+ const std::string default_name = "default";
+ int default_group_number = -1;
+ scoped_refptr<base::FieldTrial> trial_true(
+ CreateFieldTrial("d1", 10, default_name, &default_group_number));
+ ASSERT_EQ(default_group_number, trial_true->group());
+ ASSERT_EQ(default_name, trial_true->group_name());
+
+ EXPECT_EQ(EMPTY_ID,
+ GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
+ EXPECT_EQ(EMPTY_ID,
+ GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
+
+ AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
+ default_name, TEST_VALUE_A);
+ EXPECT_EQ(TEST_VALUE_A,
+ GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
+ EXPECT_EQ(EMPTY_ID,
+ GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
+
+ AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, trial_true->trial_name(),
+ default_name, TEST_VALUE_A);
+ EXPECT_EQ(TEST_VALUE_A,
+ GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
+ EXPECT_EQ(TEST_VALUE_A,
+ GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
+}
+
+TEST_F(VariationsAssociatedDataTest, AssociateVariationParams) {
+ const std::string kTrialName = "AssociateVariationParams";
+
+ {
+ std::map<std::string, std::string> params;
+ params["a"] = "10";
+ params["b"] = "test";
+ ASSERT_TRUE(AssociateVariationParams(kTrialName, "A", params));
+ }
+ {
+ std::map<std::string, std::string> params;
+ params["a"] = "5";
+ ASSERT_TRUE(AssociateVariationParams(kTrialName, "B", params));
+ }
+
+ base::FieldTrialList::CreateFieldTrial(kTrialName, "B");
+ EXPECT_EQ("5", GetVariationParamValue(kTrialName, "a"));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
+
+ std::map<std::string, std::string> params;
+ EXPECT_TRUE(GetVariationParams(kTrialName, &params));
+ EXPECT_EQ(1U, params.size());
+ EXPECT_EQ("5", params["a"]);
+}
+
+TEST_F(VariationsAssociatedDataTest, AssociateVariationParams_Fail) {
+ const std::string kTrialName = "AssociateVariationParams_Fail";
+ const std::string kGroupName = "A";
+
+ std::map<std::string, std::string> params;
+ params["a"] = "10";
+ ASSERT_TRUE(AssociateVariationParams(kTrialName, kGroupName, params));
+ params["a"] = "1";
+ params["b"] = "2";
+ ASSERT_FALSE(AssociateVariationParams(kTrialName, kGroupName, params));
+
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+ EXPECT_EQ("10", GetVariationParamValue(kTrialName, "a"));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
+}
+
+TEST_F(VariationsAssociatedDataTest, AssociateVariationParams_TrialActiveFail) {
+ const std::string kTrialName = "AssociateVariationParams_TrialActiveFail";
+ base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
+ ASSERT_EQ("A", base::FieldTrialList::FindFullName(kTrialName));
+
+ std::map<std::string, std::string> params;
+ params["a"] = "10";
+ EXPECT_FALSE(AssociateVariationParams(kTrialName, "B", params));
+ EXPECT_FALSE(AssociateVariationParams(kTrialName, "A", params));
+}
+
+TEST_F(VariationsAssociatedDataTest,
+ AssociateVariationParams_DoesntActivateTrial) {
+ const std::string kTrialName = "AssociateVariationParams_DoesntActivateTrial";
+
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+ scoped_refptr<base::FieldTrial> trial(
+ CreateFieldTrial(kTrialName, 100, "A", NULL));
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+
+ std::map<std::string, std::string> params;
+ params["a"] = "10";
+ EXPECT_TRUE(AssociateVariationParams(kTrialName, "A", params));
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParams_NoTrial) {
+ const std::string kTrialName = "GetVariationParams_NoParams";
+
+ std::map<std::string, std::string> params;
+ EXPECT_FALSE(GetVariationParams(kTrialName, &params));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParams_NoParams) {
+ const std::string kTrialName = "GetVariationParams_NoParams";
+
+ base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
+
+ std::map<std::string, std::string> params;
+ EXPECT_FALSE(GetVariationParams(kTrialName, &params));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParams_ActivatesTrial) {
+ const std::string kTrialName = "GetVariationParams_ActivatesTrial";
+
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+ scoped_refptr<base::FieldTrial> trial(
+ CreateFieldTrial(kTrialName, 100, "A", NULL));
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+
+ std::map<std::string, std::string> params;
+ EXPECT_FALSE(GetVariationParams(kTrialName, &params));
+ ASSERT_TRUE(IsFieldTrialActive(kTrialName));
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParamValue_ActivatesTrial) {
+ const std::string kTrialName = "GetVariationParamValue_ActivatesTrial";
+
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+ scoped_refptr<base::FieldTrial> trial(
+ CreateFieldTrial(kTrialName, 100, "A", NULL));
+ ASSERT_FALSE(IsFieldTrialActive(kTrialName));
+
+ std::map<std::string, std::string> params;
+ EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
+ ASSERT_TRUE(IsFieldTrialActive(kTrialName));
+}
+
+} // namespace chrome_variations
diff --git a/chrome/common/metrics/variations/variations_util.cc b/chrome/common/metrics/variations/variations_util.cc
index 2f64c92..5ef0bf8 100644
--- a/chrome/common/metrics/variations/variations_util.cc
+++ b/chrome/common/metrics/variations/variations_util.cc
@@ -4,21 +4,15 @@
#include "chrome/common/metrics/variations/variations_util.h"
-#include <map>
#include <vector>
-#include "base/memory/singleton.h"
-#include "base/sha1.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/sys_byteorder.h"
#include "chrome/common/child_process_logging.h"
-#include "chrome/common/metrics/metrics_util.h"
-#include "chrome/common/metrics/variations/variation_ids.h"
#include "chrome/installer/util/google_update_experiment_util.h"
namespace chrome_variations {
@@ -28,155 +22,6 @@ namespace {
const char kVariationPrefix[] = "CrVar";
const char kExperimentLabelSep[] = ";";
-// The internal singleton accessor for the map, used to keep it thread-safe.
-class GroupMapAccessor {
- public:
- typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
- GroupToIDMap;
-
- // Retrieve the singleton.
- static GroupMapAccessor* GetInstance() {
- return Singleton<GroupMapAccessor>::get();
- }
-
- // Note that this normally only sets the ID for a group the first time, unless
- // |force| is set to true, in which case it will always override it.
- void AssociateID(IDCollectionKey key,
- const ActiveGroupId& group_identifier,
- const VariationID id,
- const bool force) {
-#if !defined(NDEBUG)
- // Validate that all collections with this |group_identifier| have the same
- // associated ID.
- DCHECK_EQ(2, ID_COLLECTION_COUNT);
- IDCollectionKey other_key = GOOGLE_WEB_PROPERTIES;
- if (key == GOOGLE_WEB_PROPERTIES)
- other_key = GOOGLE_UPDATE_SERVICE;
- VariationID other_id = GetID(other_key, group_identifier);
- DCHECK(other_id == EMPTY_ID || other_id == id);
-#endif
-
- base::AutoLock scoped_lock(lock_);
-
- GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
- if (force ||
- group_to_id_map->find(group_identifier) == group_to_id_map->end())
- (*group_to_id_map)[group_identifier] = id;
- }
-
- VariationID GetID(IDCollectionKey key,
- const ActiveGroupId& group_identifier) {
- base::AutoLock scoped_lock(lock_);
- GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
- GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier);
- if (it == group_to_id_map->end())
- return EMPTY_ID;
- return it->second;
- }
-
- void ClearAllMapsForTesting() {
- base::AutoLock scoped_lock(lock_);
-
- for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
- GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i));
- DCHECK(map);
- map->clear();
- }
- }
-
- private:
- friend struct DefaultSingletonTraits<GroupMapAccessor>;
-
- // Retrieves the GroupToIDMap for |key|.
- GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
- return &group_to_id_maps_[key];
- }
-
- GroupMapAccessor() {
- group_to_id_maps_.resize(ID_COLLECTION_COUNT);
- }
- ~GroupMapAccessor() {}
-
- base::Lock lock_;
- std::vector<GroupToIDMap> group_to_id_maps_;
-
- DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor);
-};
-
-// Singleton helper class that keeps track of the parameters of all variations
-// and ensures access to these is thread-safe.
-class VariationsParamAssociator {
- public:
- typedef std::pair<std::string, std::string> VariationKey;
- typedef std::map<std::string, std::string> VariationParams;
-
- // Retrieve the singleton.
- static VariationsParamAssociator* GetInstance() {
- return Singleton<VariationsParamAssociator>::get();
- }
-
- bool AssociateVariationParams(const std::string& trial_name,
- const std::string& group_name,
- const VariationParams& params) {
- base::AutoLock scoped_lock(lock_);
-
- if (IsFieldTrialActive(trial_name))
- return false;
-
- const VariationKey key = VariationKey(trial_name, group_name);
- if (ContainsKey(variation_params_, key))
- return false;
-
- variation_params_[key] = params;
- return true;
- }
-
- bool GetVariationParams(const std::string& trial_name,
- VariationParams* params) {
- base::AutoLock scoped_lock(lock_);
-
- const std::string group_name =
- base::FieldTrialList::FindFullName(trial_name);
- const VariationKey key = VariationKey(trial_name, group_name);
- if (!ContainsKey(variation_params_, key))
- return false;
-
- *params = variation_params_[key];
- return true;
- }
-
- private:
- friend struct DefaultSingletonTraits<VariationsParamAssociator>;
-
- VariationsParamAssociator() {}
- ~VariationsParamAssociator() {}
-
- // Tests whether a field trial is active (i.e. group() has been called on it).
- // TODO(asvitkine): Expose this as an API on base::FieldTrial.
- bool IsFieldTrialActive(const std::string& trial_name) {
- base::FieldTrial::ActiveGroups active_groups;
- base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
- for (size_t i = 0; i < active_groups.size(); ++i) {
- if (active_groups[i].trial_name == trial_name)
- return true;
- }
- return false;
- }
-
- base::Lock lock_;
- std::map<VariationKey, VariationParams> variation_params_;
-
- DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
-};
-
-ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
- const std::string& group_name) {
- ActiveGroupId id;
- id.name = metrics::HashName(trial_name);
- id.group = metrics::HashName(group_name);
- return id;
-}
-
// Populates |name_group_ids| based on |active_groups|.
void GetFieldTrialActiveGroupIdsForActiveGroups(
const base::FieldTrial::ActiveGroups& active_groups,
@@ -193,8 +38,7 @@ void GetFieldTrialActiveGroupIdsForActiveGroups(
// including a timestamp that is a year in the future from now. Since multiple
// headers can be transmitted, |count| is a number that is appended after the
// label key to differentiate the labels.
-string16 CreateSingleExperimentLabel(int count,
- chrome_variations::VariationID id) {
+string16 CreateSingleExperimentLabel(int count, VariationID id) {
// Build the parts separately so they can be validated.
const string16 key =
ASCIIToUTF16(kVariationPrefix) + base::IntToString16(count);
@@ -234,55 +78,6 @@ void GetFieldTrialActiveGroupIdsAsStrings(
}
}
-void AssociateGoogleVariationID(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name,
- VariationID id) {
- GroupMapAccessor::GetInstance()->AssociateID(
- key, MakeActiveGroupId(trial_name, group_name), id, false);
-}
-
-void AssociateGoogleVariationIDForce(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name,
- VariationID id) {
- GroupMapAccessor::GetInstance()->AssociateID(
- key, MakeActiveGroupId(trial_name, group_name), id, true);
-}
-
-VariationID GetGoogleVariationID(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name) {
- return GroupMapAccessor::GetInstance()->GetID(
- key, MakeActiveGroupId(trial_name, group_name));
-}
-
-
-bool AssociateVariationParams(
- const std::string& trial_name,
- const std::string& group_name,
- const std::map<std::string, std::string>& params) {
- return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
- trial_name, group_name, params);
-}
-
-bool GetVariationParams(const std::string& trial_name,
- std::map<std::string, std::string>* params) {
- return VariationsParamAssociator::GetInstance()->GetVariationParams(
- trial_name, params);
-}
-
-std::string GetVariationParamValue(const std::string& trial_name,
- const std::string& param_name) {
- std::map<std::string, std::string> params;
- if (GetVariationParams(trial_name, &params)) {
- std::map<std::string, std::string>::iterator it = params.find(param_name);
- if (it != params.end())
- return it->second;
- }
- return std::string();
-}
-
void GenerateVariationChunks(const std::vector<string16>& experiments,
std::vector<string16>* chunks) {
string16 current_chunk;
@@ -316,12 +111,10 @@ string16 BuildGoogleUpdateExperimentLabel(
// Find all currently active VariationIDs associated with Google Update.
for (base::FieldTrial::ActiveGroups::const_iterator it =
active_groups.begin(); it != active_groups.end(); ++it) {
- const chrome_variations::VariationID id =
- chrome_variations::GetGoogleVariationID(
- chrome_variations::GOOGLE_UPDATE_SERVICE,
- it->trial_name, it->group_name);
+ const VariationID id = GetGoogleVariationID(GOOGLE_UPDATE_SERVICE,
+ it->trial_name, it->group_name);
- if (id == chrome_variations::EMPTY_ID)
+ if (id == EMPTY_ID)
continue;
if (!experiment_labels.empty())
@@ -374,10 +167,6 @@ string16 CombineExperimentLabels(const string16& variation_labels,
// They simply wrap existing functions in this file.
namespace testing {
-void ClearAllVariationIDs() {
- GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
-}
-
void TestGetFieldTrialActiveGroupIds(
const base::FieldTrial::ActiveGroups& active_groups,
std::vector<ActiveGroupId>* name_group_ids) {
@@ -388,4 +177,3 @@ void TestGetFieldTrialActiveGroupIds(
} // namespace testing
} // namespace chrome_variations
-
diff --git a/chrome/common/metrics/variations/variations_util.h b/chrome/common/metrics/variations/variations_util.h
index 61147b5..f6e29ed 100644
--- a/chrome/common/metrics/variations/variations_util.h
+++ b/chrome/common/metrics/variations/variations_util.h
@@ -5,80 +5,14 @@
#ifndef CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_UTIL_H_
#define CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_UTIL_H_
-#include <map>
-#include <string>
#include <vector>
#include "base/metrics/field_trial.h"
#include "base/strings/string16.h"
-#include "chrome/common/metrics/variations/variation_ids.h"
-
-// This file provides various helpers that extend the functionality around
-// base::FieldTrial.
-//
-// This includes several simple APIs to handle getting and setting additional
-// data related to Chrome variations, such as parameters and Google variation
-// IDs. These APIs are meant to extend the base::FieldTrial APIs to offer extra
-// functionality that is not offered by the simpler base::FieldTrial APIs.
-//
-// The AssociateGoogleVariationID and AssociateVariationParams functions are
-// generally meant to be called by the VariationsService based on server-side
-// variation configs, but may also be used for client-only field trials by
-// invoking them directly after appending all the groups to a FieldTrial.
-//
-// Experiment code can then use the getter APIs to retrieve variation parameters
-// or IDs:
-//
-// std::map<std::string, std::string> params;
-// if (GetVariationParams("trial", &params)) {
-// // use |params|
-// }
-//
-// std::string value = GetVariationParamValue("trial", "param_x");
-// // use |value|, which will be "" if it does not exist
-//
-// VariationID id = GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial",
-// "group1");
-// if (id != chrome_variations::kEmptyID) {
-// // use |id|
-// }
+#include "chrome/common/metrics/variations/variations_associated_data.h"
namespace chrome_variations {
-// A key into the Associate/Get methods for VariationIDs. This is used to create
-// separate ID associations for separate parties interested in VariationIDs.
-enum IDCollectionKey {
- // This collection is used by Google web properties, transmitted through the
- // X-Chrome-Variations header.
- GOOGLE_WEB_PROPERTIES,
- // This collection is used by Google update services, transmitted through the
- // Google Update experiment labels.
- GOOGLE_UPDATE_SERVICE,
- // The total count of collections.
- ID_COLLECTION_COUNT,
-};
-
-// The Unique ID of a trial and its active group, where the name and group
-// identifiers are hashes of the trial and group name strings.
-struct ActiveGroupId {
- uint32 name;
- uint32 group;
-};
-
-// We need to supply a Compare class for templates since ActiveGroupId is a
-// user-defined type.
-struct ActiveGroupIdCompare {
- bool operator() (const ActiveGroupId& lhs,
- const ActiveGroupId& rhs) const {
- // The group and name fields are just SHA-1 Hashes, so we just need to treat
- // them as IDs and do a less-than comparison. We test group first, since
- // name is more likely to collide.
- if (lhs.group != rhs.group)
- return lhs.group < rhs.group;
- return lhs.name < rhs.name;
- }
-};
-
// Fills the supplied vector |name_group_ids| (which must be empty when called)
// with unique ActiveGroupIds for each Field Trial that has a chosen group.
// Field Trials for which a group has not been chosen yet are NOT returned in
@@ -92,62 +26,6 @@ void GetFieldTrialActiveGroupIds(std::vector<ActiveGroupId>* name_group_ids);
// chosen yet are NOT returned in this list.
void GetFieldTrialActiveGroupIdsAsStrings(std::vector<string16>* output);
-// Associate a chrome_variations::VariationID value with a FieldTrial group for
-// collection |key|. If an id was previously set for |trial_name| and
-// |group_name|, this does nothing. The group is denoted by |trial_name| and
-// |group_name|. This must be called whenever a FieldTrial is prepared (create
-// the trial and append groups) and needs to have a
-// chrome_variations::VariationID associated with it so Google servers can
-// recognize the FieldTrial. Thread safe.
-void AssociateGoogleVariationID(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name,
- VariationID id);
-
-// As above, but overwrites any previously set id. Thread safe.
-void AssociateGoogleVariationIDForce(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name,
- VariationID id);
-
-// Retrieve the chrome_variations::VariationID associated with a FieldTrial
-// group for collection |key|. The group is denoted by |trial_name| and
-// |group_name|. This will return chrome_variations::kEmptyID if there is
-// currently no associated ID for the named group. This API can be nicely
-// combined with FieldTrial::GetActiveFieldTrialGroups() to enumerate the
-// variation IDs for all active FieldTrial groups. Thread safe.
-VariationID GetGoogleVariationID(IDCollectionKey key,
- const std::string& trial_name,
- const std::string& group_name);
-
-// Associates the specified set of key-value |params| with the variation
-// specified by |trial_name| and |group_name|. Fails and returns false if the
-// specified variation already has params associated with it or the field trial
-// is already active (group() has been called on it). Thread safe.
-bool AssociateVariationParams(const std::string& trial_name,
- const std::string& group_name,
- const std::map<std::string, std::string>& params);
-
-// Retrieves the set of key-value |params| for the variation associated with
-// the specified field trial, based on its selected group. If the field trial
-// does not exist or its selected group does not have any parameters associated
-// with it, returns false and does not modify |params|. Calling this function
-// will result in the field trial being marked as active if found (i.e. group()
-// will be called on it), if it wasn't already. Currently, this information is
-// only available from the browser process. Thread safe.
-bool GetVariationParams(const std::string& trial_name,
- std::map<std::string, std::string>* params);
-
-// Retrieves a specific parameter value corresponding to |param_name| for the
-// variation associated with the specified field trial, based on its selected
-// group. If the field trial does not exist or the specified parameter does not
-// exist, returns an empty string. Calling this function will result in the
-// field trial being marked as active if found (i.e. group() will be called on
-// it), if it wasn't already. Currently, this information is only available from
-// the browser process. Thread safe.
-std::string GetVariationParamValue(const std::string& trial_name,
- const std::string& param_name);
-
// Generates variation chunks from |variation_strings| that are suitable for
// crash reporting.
void GenerateVariationChunks(const std::vector<string16>& variation_strings,
diff --git a/chrome/common/metrics/variations/variations_util_unittest.cc b/chrome/common/metrics/variations/variations_util_unittest.cc
index 173133a..c92da5b 100644
--- a/chrome/common/metrics/variations/variations_util_unittest.cc
+++ b/chrome/common/metrics/variations/variations_util_unittest.cc
@@ -2,32 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Tests for the Variations Helpers.
+#include "chrome/common/metrics/variations/variations_util.h"
#include <set>
+#include <string>
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/common/metrics/metrics_util.h"
-#include "chrome/common/metrics/variations/variations_util.h"
-#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chrome_variations {
namespace {
-// Convenience helper to retrieve the chrome_variations::VariationID for a
-// FieldTrial. Note that this will do the group assignment in |trial| if not
-// already done.
-VariationID GetIDForTrial(IDCollectionKey key, base::FieldTrial* trial) {
- return GetGoogleVariationID(key, trial->trial_name(), trial->group_name());
-}
-
// Tests whether a field trial is active (i.e. group() has been called on it).
bool IsFieldTrialActive(const std::string& trial_name) {
base::FieldTrial::ActiveGroups active_groups;
@@ -56,11 +46,9 @@ scoped_refptr<base::FieldTrial> CreateFieldTrial(
class VariationsUtilTest : public ::testing::Test {
public:
VariationsUtilTest() : field_trial_list_(NULL) {
- // Since the API can only be called on the UI thread, we have to fake that
- // we're on it.
- ui_thread_.reset(new content::TestBrowserThread(
- content::BrowserThread::UI, &message_loop_));
+ }
+ virtual ~VariationsUtilTest() {
// Ensure that the maps are cleared between tests, since they are stored as
// process singletons.
testing::ClearAllVariationIDs();
@@ -68,8 +56,8 @@ class VariationsUtilTest : public ::testing::Test {
private:
base::FieldTrialList field_trial_list_;
- base::MessageLoop message_loop_;
- scoped_ptr<content::TestBrowserThread> ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(VariationsUtilTest);
};
TEST_F(VariationsUtilTest, GetFieldTrialActiveGroups) {
@@ -111,220 +99,6 @@ TEST_F(VariationsUtilTest, GetFieldTrialActiveGroups) {
EXPECT_EQ(0U, expected_groups.size());
}
-// Test that if the trial is immediately disabled, GetGoogleVariationID just
-// returns the empty ID.
-TEST_F(VariationsUtilTest, DisableImmediately) {
- int default_group_number = -1;
- scoped_refptr<base::FieldTrial> trial(
- CreateFieldTrial("trial", 100, "default", &default_group_number));
-
- ASSERT_EQ(default_group_number, trial->group());
- ASSERT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
-}
-
-// Test that successfully associating the FieldTrial with some ID, and then
-// disabling the FieldTrial actually makes GetGoogleVariationID correctly
-// return the empty ID.
-TEST_F(VariationsUtilTest, DisableAfterInitialization) {
- const std::string default_name = "default";
- const std::string non_default_name = "non_default";
-
- scoped_refptr<base::FieldTrial> trial(
- CreateFieldTrial("trial", 100, default_name, NULL));
-
- trial->AppendGroup(non_default_name, 100);
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
- default_name, TEST_VALUE_A);
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
- non_default_name, TEST_VALUE_B);
- trial->Disable();
- ASSERT_EQ(default_name, trial->group_name());
- ASSERT_EQ(TEST_VALUE_A, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
-}
-
-// Test various successful association cases.
-TEST_F(VariationsUtilTest, AssociateGoogleVariationID) {
- const std::string default_name1 = "default";
- scoped_refptr<base::FieldTrial> trial_true(
- CreateFieldTrial("d1", 10, default_name1, NULL));
- const std::string winner = "TheWinner";
- int winner_group = trial_true->AppendGroup(winner, 10);
-
- // Set GoogleVariationIDs so we can verify that they were chosen correctly.
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
- default_name1, TEST_VALUE_A);
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
- winner, TEST_VALUE_B);
-
- EXPECT_EQ(winner_group, trial_true->group());
- EXPECT_EQ(winner, trial_true->group_name());
- EXPECT_EQ(TEST_VALUE_B,
- GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
-
- const std::string default_name2 = "default2";
- scoped_refptr<base::FieldTrial> trial_false(
- CreateFieldTrial("d2", 10, default_name2, NULL));
- const std::string loser = "ALoser";
- const int loser_group = trial_false->AppendGroup(loser, 0);
-
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
- default_name2, TEST_VALUE_A);
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
- loser, TEST_VALUE_B);
-
- EXPECT_NE(loser_group, trial_false->group());
- EXPECT_EQ(TEST_VALUE_A,
- GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_false.get()));
-}
-
-// Test that not associating a FieldTrial with any IDs ensure that the empty ID
-// will be returned.
-TEST_F(VariationsUtilTest, NoAssociation) {
- const std::string default_name = "default";
- scoped_refptr<base::FieldTrial> no_id_trial(
- CreateFieldTrial("d3", 10, default_name, NULL));
-
- const std::string winner = "TheWinner";
- const int winner_group = no_id_trial->AppendGroup(winner, 10);
-
- // Ensure that despite the fact that a normal winner is elected, it does not
- // have a valid VariationID associated with it.
- EXPECT_EQ(winner_group, no_id_trial->group());
- EXPECT_EQ(winner, no_id_trial->group_name());
- EXPECT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, no_id_trial.get()));
-}
-
-// Ensure that the AssociateGoogleVariationIDForce works as expected.
-TEST_F(VariationsUtilTest, ForceAssociation) {
- EXPECT_EQ(EMPTY_ID,
- GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
- TEST_VALUE_A);
- EXPECT_EQ(TEST_VALUE_A,
- GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
- TEST_VALUE_B);
- EXPECT_EQ(TEST_VALUE_A,
- GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
- AssociateGoogleVariationIDForce(GOOGLE_WEB_PROPERTIES, "trial", "group",
- TEST_VALUE_B);
- EXPECT_EQ(TEST_VALUE_B,
- GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
-}
-
-TEST_F(VariationsUtilTest, AssociateVariationParams) {
- const std::string kTrialName = "AssociateVariationParams";
-
- {
- std::map<std::string, std::string> params;
- params["a"] = "10";
- params["b"] = "test";
- ASSERT_TRUE(AssociateVariationParams(kTrialName, "A", params));
- }
- {
- std::map<std::string, std::string> params;
- params["a"] = "5";
- ASSERT_TRUE(AssociateVariationParams(kTrialName, "B", params));
- }
-
- base::FieldTrialList::CreateFieldTrial(kTrialName, "B");
- EXPECT_EQ("5", GetVariationParamValue(kTrialName, "a"));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
-
- std::map<std::string, std::string> params;
- EXPECT_TRUE(GetVariationParams(kTrialName, &params));
- EXPECT_EQ(1U, params.size());
- EXPECT_EQ("5", params["a"]);
-}
-
-TEST_F(VariationsUtilTest, AssociateVariationParams_Fail) {
- const std::string kTrialName = "AssociateVariationParams_Fail";
- const std::string kGroupName = "A";
-
- std::map<std::string, std::string> params;
- params["a"] = "10";
- ASSERT_TRUE(AssociateVariationParams(kTrialName, kGroupName, params));
- params["a"] = "1";
- params["b"] = "2";
- ASSERT_FALSE(AssociateVariationParams(kTrialName, kGroupName, params));
-
- base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
- EXPECT_EQ("10", GetVariationParamValue(kTrialName, "a"));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
-}
-
-TEST_F(VariationsUtilTest, AssociateVariationParams_TrialActiveFail) {
- const std::string kTrialName = "AssociateVariationParams_TrialActiveFail";
- base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
- ASSERT_EQ("A", base::FieldTrialList::FindFullName(kTrialName));
-
- std::map<std::string, std::string> params;
- params["a"] = "10";
- EXPECT_FALSE(AssociateVariationParams(kTrialName, "B", params));
- EXPECT_FALSE(AssociateVariationParams(kTrialName, "A", params));
-}
-
-TEST_F(VariationsUtilTest, AssociateVariationParams_DoesntActivateTrial) {
- const std::string kTrialName = "AssociateVariationParams_DoesntActivateTrial";
-
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
- scoped_refptr<base::FieldTrial> trial(
- CreateFieldTrial(kTrialName, 100, "A", NULL));
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
-
- std::map<std::string, std::string> params;
- params["a"] = "10";
- EXPECT_TRUE(AssociateVariationParams(kTrialName, "A", params));
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
-}
-
-TEST_F(VariationsUtilTest, GetVariationParams_NoTrial) {
- const std::string kTrialName = "GetVariationParams_NoParams";
-
- std::map<std::string, std::string> params;
- EXPECT_FALSE(GetVariationParams(kTrialName, &params));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
-}
-
-TEST_F(VariationsUtilTest, GetVariationParams_NoParams) {
- const std::string kTrialName = "GetVariationParams_NoParams";
-
- base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
-
- std::map<std::string, std::string> params;
- EXPECT_FALSE(GetVariationParams(kTrialName, &params));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
-}
-
-TEST_F(VariationsUtilTest, GetVariationParams_ActivatesTrial) {
- const std::string kTrialName = "GetVariationParams_ActivatesTrial";
-
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
- scoped_refptr<base::FieldTrial> trial(
- CreateFieldTrial(kTrialName, 100, "A", NULL));
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
-
- std::map<std::string, std::string> params;
- EXPECT_FALSE(GetVariationParams(kTrialName, &params));
- ASSERT_TRUE(IsFieldTrialActive(kTrialName));
-}
-
-TEST_F(VariationsUtilTest, GetVariationParamValue_ActivatesTrial) {
- const std::string kTrialName = "GetVariationParamValue_ActivatesTrial";
-
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
- scoped_refptr<base::FieldTrial> trial(
- CreateFieldTrial(kTrialName, 100, "A", NULL));
- ASSERT_FALSE(IsFieldTrialActive(kTrialName));
-
- std::map<std::string, std::string> params;
- EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
- ASSERT_TRUE(IsFieldTrialActive(kTrialName));
-}
-
TEST_F(VariationsUtilTest, GenerateExperimentChunks) {
const char* kExperimentStrings[] = {
"1d3048f1-9de009d0",
@@ -379,35 +153,6 @@ TEST_F(VariationsUtilTest, GenerateExperimentChunks) {
}
}
-// Ensure that two collections can coexist without affecting each other.
-TEST_F(VariationsUtilTest, CollectionsCoexist) {
- const std::string default_name = "default";
- int default_group_number = -1;
- scoped_refptr<base::FieldTrial> trial_true(
- CreateFieldTrial("d1", 10, default_name, &default_group_number));
- ASSERT_EQ(default_group_number, trial_true->group());
- ASSERT_EQ(default_name, trial_true->group_name());
-
- EXPECT_EQ(EMPTY_ID,
- GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
- EXPECT_EQ(EMPTY_ID,
- GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
-
- AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
- default_name, TEST_VALUE_A);
- EXPECT_EQ(TEST_VALUE_A,
- GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
- EXPECT_EQ(EMPTY_ID,
- GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
-
- AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, trial_true->trial_name(),
- default_name, TEST_VALUE_A);
- EXPECT_EQ(TEST_VALUE_A,
- GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
- EXPECT_EQ(TEST_VALUE_A,
- GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
-}
-
TEST_F(VariationsUtilTest, BuildGoogleUpdateExperimentLabel) {
struct {
const char* active_group_pairs;
@@ -431,18 +176,14 @@ TEST_F(VariationsUtilTest, BuildGoogleUpdateExperimentLabel) {
};
// Register a few VariationIDs.
- chrome_variations::AssociateGoogleVariationID(
- chrome_variations::GOOGLE_UPDATE_SERVICE, "FieldTrialA", "Default",
- chrome_variations::TEST_VALUE_A);
- chrome_variations::AssociateGoogleVariationID(
- chrome_variations::GOOGLE_UPDATE_SERVICE, "FieldTrialB", "Group1",
- chrome_variations::TEST_VALUE_B);
- chrome_variations::AssociateGoogleVariationID(
- chrome_variations::GOOGLE_UPDATE_SERVICE, "FieldTrialC", "Default",
- chrome_variations::TEST_VALUE_C);
- chrome_variations::AssociateGoogleVariationID(
- chrome_variations::GOOGLE_UPDATE_SERVICE, "FieldTrialD", "Default",
- chrome_variations::TEST_VALUE_D); // Not actually used.
+ AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, "FieldTrialA", "Default",
+ TEST_VALUE_A);
+ AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, "FieldTrialB", "Group1",
+ TEST_VALUE_B);
+ AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, "FieldTrialC", "Default",
+ TEST_VALUE_C);
+ AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, "FieldTrialD", "Default",
+ TEST_VALUE_D); // Not actually used.
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
// Parse the input groups.