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 "base/metrics/field_trial.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace chrome_variations {
11
12namespace {
13
14const VariationID TEST_VALUE_A = 3300200;
15const VariationID TEST_VALUE_B = 3300201;
16
17// Convenience helper to retrieve the chrome_variations::VariationID for a
18// FieldTrial. Note that this will do the group assignment in |trial| if not
19// already done.
20VariationID GetIDForTrial(IDCollectionKey key, base::FieldTrial* trial) {
21  return GetGoogleVariationID(key, trial->trial_name(), trial->group_name());
22}
23
24// Tests whether a field trial is active (i.e. group() has been called on it).
25bool IsFieldTrialActive(const std::string& trial_name) {
26  base::FieldTrial::ActiveGroups active_groups;
27  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
28  for (size_t i = 0; i < active_groups.size(); ++i) {
29    if (active_groups[i].trial_name == trial_name)
30      return true;
31  }
32  return false;
33}
34
35// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
36scoped_refptr<base::FieldTrial> CreateFieldTrial(
37    const std::string& trial_name,
38    int total_probability,
39    const std::string& default_group_name,
40    int* default_group_number) {
41  return base::FieldTrialList::FactoryGetFieldTrial(
42      trial_name, total_probability, default_group_name,
43      base::FieldTrialList::kNoExpirationYear, 1, 1,
44      base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
45}
46
47}  // namespace
48
49class VariationsAssociatedDataTest : public ::testing::Test {
50 public:
51  VariationsAssociatedDataTest() : field_trial_list_(NULL) {
52  }
53
54  virtual ~VariationsAssociatedDataTest() {
55    // Ensure that the maps are cleared between tests, since they are stored as
56    // process singletons.
57    testing::ClearAllVariationIDs();
58    testing::ClearAllVariationParams();
59  }
60
61 private:
62  base::FieldTrialList field_trial_list_;
63
64  DISALLOW_COPY_AND_ASSIGN(VariationsAssociatedDataTest);
65};
66
67// Test that if the trial is immediately disabled, GetGoogleVariationID just
68// returns the empty ID.
69TEST_F(VariationsAssociatedDataTest, DisableImmediately) {
70  int default_group_number = -1;
71  scoped_refptr<base::FieldTrial> trial(
72      CreateFieldTrial("trial", 100, "default", &default_group_number));
73
74  ASSERT_EQ(default_group_number, trial->group());
75  ASSERT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
76}
77
78// Test that successfully associating the FieldTrial with some ID, and then
79// disabling the FieldTrial actually makes GetGoogleVariationID correctly
80// return the empty ID.
81TEST_F(VariationsAssociatedDataTest, DisableAfterInitialization) {
82  const std::string default_name = "default";
83  const std::string non_default_name = "non_default";
84
85  scoped_refptr<base::FieldTrial> trial(
86      CreateFieldTrial("trial", 100, default_name, NULL));
87
88  trial->AppendGroup(non_default_name, 100);
89  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
90      default_name, TEST_VALUE_A);
91  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial->trial_name(),
92      non_default_name, TEST_VALUE_B);
93  trial->Disable();
94  ASSERT_EQ(default_name, trial->group_name());
95  ASSERT_EQ(TEST_VALUE_A, GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial.get()));
96}
97
98// Test various successful association cases.
99TEST_F(VariationsAssociatedDataTest, AssociateGoogleVariationID) {
100  const std::string default_name1 = "default";
101  scoped_refptr<base::FieldTrial> trial_true(
102      CreateFieldTrial("d1", 10, default_name1, NULL));
103  const std::string winner = "TheWinner";
104  int winner_group = trial_true->AppendGroup(winner, 10);
105
106  // Set GoogleVariationIDs so we can verify that they were chosen correctly.
107  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
108      default_name1, TEST_VALUE_A);
109  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
110      winner, TEST_VALUE_B);
111
112  EXPECT_EQ(winner_group, trial_true->group());
113  EXPECT_EQ(winner, trial_true->group_name());
114  EXPECT_EQ(TEST_VALUE_B,
115            GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
116
117  const std::string default_name2 = "default2";
118  scoped_refptr<base::FieldTrial> trial_false(
119      CreateFieldTrial("d2", 10, default_name2, NULL));
120  const std::string loser = "ALoser";
121  const int loser_group = trial_false->AppendGroup(loser, 0);
122
123  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
124      default_name2, TEST_VALUE_A);
125  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_false->trial_name(),
126      loser, TEST_VALUE_B);
127
128  EXPECT_NE(loser_group, trial_false->group());
129  EXPECT_EQ(TEST_VALUE_A,
130            GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_false.get()));
131}
132
133// Test that not associating a FieldTrial with any IDs ensure that the empty ID
134// will be returned.
135TEST_F(VariationsAssociatedDataTest, NoAssociation) {
136  const std::string default_name = "default";
137  scoped_refptr<base::FieldTrial> no_id_trial(
138      CreateFieldTrial("d3", 10, default_name, NULL));
139
140  const std::string winner = "TheWinner";
141  const int winner_group = no_id_trial->AppendGroup(winner, 10);
142
143  // Ensure that despite the fact that a normal winner is elected, it does not
144  // have a valid VariationID associated with it.
145  EXPECT_EQ(winner_group, no_id_trial->group());
146  EXPECT_EQ(winner, no_id_trial->group_name());
147  EXPECT_EQ(EMPTY_ID, GetIDForTrial(GOOGLE_WEB_PROPERTIES, no_id_trial.get()));
148}
149
150// Ensure that the AssociateGoogleVariationIDForce works as expected.
151TEST_F(VariationsAssociatedDataTest, ForceAssociation) {
152  EXPECT_EQ(EMPTY_ID,
153            GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
154  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
155                             TEST_VALUE_A);
156  EXPECT_EQ(TEST_VALUE_A,
157            GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
158  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group",
159                             TEST_VALUE_B);
160  EXPECT_EQ(TEST_VALUE_A,
161            GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
162  AssociateGoogleVariationIDForce(GOOGLE_WEB_PROPERTIES, "trial", "group",
163                                  TEST_VALUE_B);
164  EXPECT_EQ(TEST_VALUE_B,
165            GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, "trial", "group"));
166}
167
168// Ensure that two collections can coexist without affecting each other.
169TEST_F(VariationsAssociatedDataTest, CollectionsCoexist) {
170  const std::string default_name = "default";
171  int default_group_number = -1;
172  scoped_refptr<base::FieldTrial> trial_true(
173      CreateFieldTrial("d1", 10, default_name, &default_group_number));
174  ASSERT_EQ(default_group_number, trial_true->group());
175  ASSERT_EQ(default_name, trial_true->group_name());
176
177  EXPECT_EQ(EMPTY_ID,
178            GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
179  EXPECT_EQ(EMPTY_ID,
180            GetIDForTrial(GOOGLE_WEB_PROPERTIES_TRIGGER, trial_true.get()));
181  EXPECT_EQ(EMPTY_ID,
182            GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
183
184  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_true->trial_name(),
185      default_name, TEST_VALUE_A);
186  EXPECT_EQ(TEST_VALUE_A,
187            GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
188  EXPECT_EQ(EMPTY_ID,
189            GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
190
191  AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, trial_true->trial_name(),
192      default_name, TEST_VALUE_A);
193  EXPECT_EQ(TEST_VALUE_A,
194            GetIDForTrial(GOOGLE_WEB_PROPERTIES, trial_true.get()));
195  EXPECT_EQ(TEST_VALUE_A,
196            GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
197
198  trial_true = CreateFieldTrial("d2", 10, default_name, &default_group_number);
199  ASSERT_EQ(default_group_number, trial_true->group());
200  ASSERT_EQ(default_name, trial_true->group_name());
201
202  AssociateGoogleVariationID(GOOGLE_WEB_PROPERTIES_TRIGGER,
203                             trial_true->trial_name(), default_name,
204                             TEST_VALUE_A);
205  EXPECT_EQ(TEST_VALUE_A,
206            GetIDForTrial(GOOGLE_WEB_PROPERTIES_TRIGGER, trial_true.get()));
207  EXPECT_EQ(EMPTY_ID,
208            GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
209
210  AssociateGoogleVariationID(GOOGLE_UPDATE_SERVICE, trial_true->trial_name(),
211                             default_name, TEST_VALUE_A);
212  EXPECT_EQ(TEST_VALUE_A,
213            GetIDForTrial(GOOGLE_WEB_PROPERTIES_TRIGGER, trial_true.get()));
214  EXPECT_EQ(TEST_VALUE_A,
215            GetIDForTrial(GOOGLE_UPDATE_SERVICE, trial_true.get()));
216}
217
218TEST_F(VariationsAssociatedDataTest, AssociateVariationParams) {
219  const std::string kTrialName = "AssociateVariationParams";
220
221  {
222    std::map<std::string, std::string> params;
223    params["a"] = "10";
224    params["b"] = "test";
225    ASSERT_TRUE(AssociateVariationParams(kTrialName, "A", params));
226  }
227  {
228    std::map<std::string, std::string> params;
229    params["a"] = "5";
230    ASSERT_TRUE(AssociateVariationParams(kTrialName, "B", params));
231  }
232
233  base::FieldTrialList::CreateFieldTrial(kTrialName, "B");
234  EXPECT_EQ("5", GetVariationParamValue(kTrialName, "a"));
235  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
236  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
237
238  std::map<std::string, std::string> params;
239  EXPECT_TRUE(GetVariationParams(kTrialName, &params));
240  EXPECT_EQ(1U, params.size());
241  EXPECT_EQ("5", params["a"]);
242}
243
244TEST_F(VariationsAssociatedDataTest, AssociateVariationParams_Fail) {
245  const std::string kTrialName = "AssociateVariationParams_Fail";
246  const std::string kGroupName = "A";
247
248  std::map<std::string, std::string> params;
249  params["a"] = "10";
250  ASSERT_TRUE(AssociateVariationParams(kTrialName, kGroupName, params));
251  params["a"] = "1";
252  params["b"] = "2";
253  ASSERT_FALSE(AssociateVariationParams(kTrialName, kGroupName, params));
254
255  base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
256  EXPECT_EQ("10", GetVariationParamValue(kTrialName, "a"));
257  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "b"));
258}
259
260TEST_F(VariationsAssociatedDataTest, AssociateVariationParams_TrialActiveFail) {
261  const std::string kTrialName = "AssociateVariationParams_TrialActiveFail";
262  base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
263  ASSERT_EQ("A", base::FieldTrialList::FindFullName(kTrialName));
264
265  std::map<std::string, std::string> params;
266  params["a"] = "10";
267  EXPECT_FALSE(AssociateVariationParams(kTrialName, "B", params));
268  EXPECT_FALSE(AssociateVariationParams(kTrialName, "A", params));
269}
270
271TEST_F(VariationsAssociatedDataTest,
272       AssociateVariationParams_DoesntActivateTrial) {
273  const std::string kTrialName = "AssociateVariationParams_DoesntActivateTrial";
274
275  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
276  scoped_refptr<base::FieldTrial> trial(
277      CreateFieldTrial(kTrialName, 100, "A", NULL));
278  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
279
280  std::map<std::string, std::string> params;
281  params["a"] = "10";
282  EXPECT_TRUE(AssociateVariationParams(kTrialName, "A", params));
283  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
284}
285
286TEST_F(VariationsAssociatedDataTest, GetVariationParams_NoTrial) {
287  const std::string kTrialName = "GetVariationParams_NoParams";
288
289  std::map<std::string, std::string> params;
290  EXPECT_FALSE(GetVariationParams(kTrialName, &params));
291  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
292  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
293}
294
295TEST_F(VariationsAssociatedDataTest, GetVariationParams_NoParams) {
296  const std::string kTrialName = "GetVariationParams_NoParams";
297
298  base::FieldTrialList::CreateFieldTrial(kTrialName, "A");
299
300  std::map<std::string, std::string> params;
301  EXPECT_FALSE(GetVariationParams(kTrialName, &params));
302  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
303  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "y"));
304}
305
306TEST_F(VariationsAssociatedDataTest, GetVariationParams_ActivatesTrial) {
307  const std::string kTrialName = "GetVariationParams_ActivatesTrial";
308
309  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
310  scoped_refptr<base::FieldTrial> trial(
311      CreateFieldTrial(kTrialName, 100, "A", NULL));
312  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
313
314  std::map<std::string, std::string> params;
315  EXPECT_FALSE(GetVariationParams(kTrialName, &params));
316  ASSERT_TRUE(IsFieldTrialActive(kTrialName));
317}
318
319TEST_F(VariationsAssociatedDataTest, GetVariationParamValue_ActivatesTrial) {
320  const std::string kTrialName = "GetVariationParamValue_ActivatesTrial";
321
322  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
323  scoped_refptr<base::FieldTrial> trial(
324      CreateFieldTrial(kTrialName, 100, "A", NULL));
325  ASSERT_FALSE(IsFieldTrialActive(kTrialName));
326
327  std::map<std::string, std::string> params;
328  EXPECT_EQ(std::string(), GetVariationParamValue(kTrialName, "x"));
329  ASSERT_TRUE(IsFieldTrialActive(kTrialName));
330}
331
332}  // namespace chrome_variations
333