Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / variations / variations_associated_data.cc
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
3 // found in the LICENSE file.
4
5 #include "components/variations/variations_associated_data.h"
6
7 #include <map>
8 #include <utility>
9 #include <vector>
10
11 #include "base/memory/singleton.h"
12 #include "components/variations/metrics_util.h"
13
14 namespace chrome_variations {
15
16 namespace {
17
18 // The internal singleton accessor for the map, used to keep it thread-safe.
19 class GroupMapAccessor {
20  public:
21   typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
22       GroupToIDMap;
23
24   // Retrieve the singleton.
25   static GroupMapAccessor* GetInstance() {
26     return Singleton<GroupMapAccessor>::get();
27   }
28
29   // Note that this normally only sets the ID for a group the first time, unless
30   // |force| is set to true, in which case it will always override it.
31   void AssociateID(IDCollectionKey key,
32                    const ActiveGroupId& group_identifier,
33                    const VariationID id,
34                    const bool force) {
35 #if !defined(NDEBUG)
36     DCHECK_EQ(3, ID_COLLECTION_COUNT);
37     // Ensure that at most one of the trigger/non-trigger web property IDs are
38     // set.
39     if (key == GOOGLE_WEB_PROPERTIES || key == GOOGLE_WEB_PROPERTIES_TRIGGER) {
40       IDCollectionKey other_key = key == GOOGLE_WEB_PROPERTIES ?
41           GOOGLE_WEB_PROPERTIES_TRIGGER : GOOGLE_WEB_PROPERTIES;
42       DCHECK_EQ(EMPTY_ID, GetID(other_key, group_identifier));
43     }
44
45     // Validate that all collections with this |group_identifier| have the same
46     // associated ID.
47     for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
48       IDCollectionKey other_key = static_cast<IDCollectionKey>(i);
49       if (other_key == key)
50         continue;
51       VariationID other_id = GetID(other_key, group_identifier);
52       DCHECK(other_id == EMPTY_ID || other_id == id);
53     }
54 #endif
55
56     base::AutoLock scoped_lock(lock_);
57
58     GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
59     if (force ||
60         group_to_id_map->find(group_identifier) == group_to_id_map->end())
61       (*group_to_id_map)[group_identifier] = id;
62   }
63
64   VariationID GetID(IDCollectionKey key,
65                     const ActiveGroupId& group_identifier) {
66     base::AutoLock scoped_lock(lock_);
67     GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
68     GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier);
69     if (it == group_to_id_map->end())
70       return EMPTY_ID;
71     return it->second;
72   }
73
74   void ClearAllMapsForTesting() {
75     base::AutoLock scoped_lock(lock_);
76
77     for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
78       GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i));
79       DCHECK(map);
80       map->clear();
81     }
82   }
83
84  private:
85   friend struct DefaultSingletonTraits<GroupMapAccessor>;
86
87   // Retrieves the GroupToIDMap for |key|.
88   GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
89     return &group_to_id_maps_[key];
90   }
91
92   GroupMapAccessor() {
93     group_to_id_maps_.resize(ID_COLLECTION_COUNT);
94   }
95   ~GroupMapAccessor() {}
96
97   base::Lock lock_;
98   std::vector<GroupToIDMap> group_to_id_maps_;
99
100   DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor);
101 };
102
103 // Singleton helper class that keeps track of the parameters of all variations
104 // and ensures access to these is thread-safe.
105 class VariationsParamAssociator {
106  public:
107   typedef std::pair<std::string, std::string> VariationKey;
108   typedef std::map<std::string, std::string> VariationParams;
109
110   // Retrieve the singleton.
111   static VariationsParamAssociator* GetInstance() {
112     return Singleton<VariationsParamAssociator>::get();
113   }
114
115   bool AssociateVariationParams(const std::string& trial_name,
116                                 const std::string& group_name,
117                                 const VariationParams& params) {
118     base::AutoLock scoped_lock(lock_);
119
120     if (IsFieldTrialActive(trial_name))
121       return false;
122
123     const VariationKey key(trial_name, group_name);
124     if (ContainsKey(variation_params_, key))
125       return false;
126
127     variation_params_[key] = params;
128     return true;
129   }
130
131   bool GetVariationParams(const std::string& trial_name,
132                           VariationParams* params) {
133     base::AutoLock scoped_lock(lock_);
134
135     const std::string group_name =
136         base::FieldTrialList::FindFullName(trial_name);
137     const VariationKey key(trial_name, group_name);
138     if (!ContainsKey(variation_params_, key))
139       return false;
140
141     *params = variation_params_[key];
142     return true;
143   }
144
145   void ClearAllParamsForTesting() {
146     base::AutoLock scoped_lock(lock_);
147     variation_params_.clear();
148   }
149
150  private:
151   friend struct DefaultSingletonTraits<VariationsParamAssociator>;
152
153   VariationsParamAssociator() {}
154   ~VariationsParamAssociator() {}
155
156   // Tests whether a field trial is active (i.e. group() has been called on it).
157   // TODO(asvitkine): Expose this as an API on base::FieldTrial.
158   bool IsFieldTrialActive(const std::string& trial_name) {
159     base::FieldTrial::ActiveGroups active_groups;
160     base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
161     for (size_t i = 0; i < active_groups.size(); ++i) {
162       if (active_groups[i].trial_name == trial_name)
163         return true;
164     }
165     return false;
166   }
167
168   base::Lock lock_;
169   std::map<VariationKey, VariationParams> variation_params_;
170
171   DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
172 };
173
174 }  // namespace
175
176 ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
177                                 const std::string& group_name) {
178   ActiveGroupId id;
179   id.name = metrics::HashName(trial_name);
180   id.group = metrics::HashName(group_name);
181   return id;
182 }
183
184 void AssociateGoogleVariationID(IDCollectionKey key,
185                                 const std::string& trial_name,
186                                 const std::string& group_name,
187                                 VariationID id) {
188   GroupMapAccessor::GetInstance()->AssociateID(
189       key, MakeActiveGroupId(trial_name, group_name), id, false);
190 }
191
192 void AssociateGoogleVariationIDForce(IDCollectionKey key,
193                                      const std::string& trial_name,
194                                      const std::string& group_name,
195                                      VariationID id) {
196   GroupMapAccessor::GetInstance()->AssociateID(
197       key, MakeActiveGroupId(trial_name, group_name), id, true);
198 }
199
200 VariationID GetGoogleVariationID(IDCollectionKey key,
201                                  const std::string& trial_name,
202                                  const std::string& group_name) {
203   return GroupMapAccessor::GetInstance()->GetID(
204       key, MakeActiveGroupId(trial_name, group_name));
205 }
206
207 bool AssociateVariationParams(
208     const std::string& trial_name,
209     const std::string& group_name,
210     const std::map<std::string, std::string>& params) {
211   return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
212       trial_name, group_name, params);
213 }
214
215 bool GetVariationParams(const std::string& trial_name,
216                         std::map<std::string, std::string>* params) {
217   return VariationsParamAssociator::GetInstance()->GetVariationParams(
218       trial_name, params);
219 }
220
221 std::string GetVariationParamValue(const std::string& trial_name,
222                                    const std::string& param_name) {
223   std::map<std::string, std::string> params;
224   if (GetVariationParams(trial_name, &params)) {
225     std::map<std::string, std::string>::iterator it = params.find(param_name);
226     if (it != params.end())
227       return it->second;
228   }
229   return std::string();
230 }
231
232 // Functions below are exposed for testing explicitly behind this namespace.
233 // They simply wrap existing functions in this file.
234 namespace testing {
235
236 void ClearAllVariationIDs() {
237   GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
238 }
239
240 void ClearAllVariationParams() {
241   VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
242 }
243
244 }  // namespace testing
245
246 }  // namespace chrome_variations