blob: e7ef847cd91a91425a16fdf9190dd77af2d0c28b [file] [log] [blame]
Steven Holtef58f2b22017-07-17 18:43:451// Copyright 2017 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/synthetic_trial_registry.h"
6
7#include "base/strings/stringprintf.h"
8#include "components/variations/active_field_trials.h"
Alexei Svitkine9de32cb2018-02-06 20:21:219#include "components/variations/hashing.h"
Steven Holtef58f2b22017-07-17 18:43:4510#include "components/variations/synthetic_trials_active_group_id_provider.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace variations {
14
15namespace {
16
17class SyntheticTrialRegistryTest : public ::testing::Test {
18 public:
19 // Returns true if there is a synthetic trial in the given vector that matches
20 // the given trial name and trial group; returns false otherwise.
21 bool HasSyntheticTrial(const std::vector<ActiveGroupId>& synthetic_trials,
22 const std::string& trial_name,
23 const std::string& trial_group) {
Alexei Svitkine9de32cb2018-02-06 20:21:2124 uint32_t trial_name_hash = HashName(trial_name);
25 uint32_t trial_group_hash = HashName(trial_group);
Steven Holtef58f2b22017-07-17 18:43:4526 for (const ActiveGroupId& trial : synthetic_trials) {
27 if (trial.name == trial_name_hash && trial.group == trial_group_hash)
28 return true;
29 }
30 return false;
31 }
32
33 // Waits until base::TimeTicks::Now() no longer equals |value|. This should
34 // take between 1-15ms per the documented resolution of base::TimeTicks.
35 void WaitUntilTimeChanges(const base::TimeTicks& value) {
36 while (base::TimeTicks::Now() == value) {
37 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
38 }
39 }
40};
41
42} // namespace
43
44TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticTrial) {
45 SyntheticTrialRegistry registry;
46
47 // Add two synthetic trials and confirm that they show up in the list.
Alexei Svitkine9de32cb2018-02-06 20:21:2148 SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
Steven Holtef58f2b22017-07-17 18:43:4549 registry.RegisterSyntheticFieldTrial(trial1);
50
Alexei Svitkine9de32cb2018-02-06 20:21:2151 SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:4552 registry.RegisterSyntheticFieldTrial(trial2);
53 // Ensure that time has advanced by at least a tick before proceeding.
54 WaitUntilTimeChanges(base::TimeTicks::Now());
55
56 // Save the time when the log was started (it's okay for this to be greater
57 // than the time recorded by the above call since it's used to ensure the
58 // value changes).
59 const base::TimeTicks begin_log_time = base::TimeTicks::Now();
60
61 std::vector<ActiveGroupId> synthetic_trials;
62 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
63 &synthetic_trials);
64 EXPECT_EQ(2U, synthetic_trials.size());
65 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1"));
66 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
67
68 // Ensure that time has advanced by at least a tick before proceeding.
69 WaitUntilTimeChanges(begin_log_time);
70
71 // Change the group for the first trial after the log started.
Alexei Svitkine9de32cb2018-02-06 20:21:2172 SyntheticTrialGroup trial3(HashName("TestTrial1"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:4573 registry.RegisterSyntheticFieldTrial(trial3);
74 registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
75 EXPECT_EQ(1U, synthetic_trials.size());
76 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
77
78 // Add a new trial after the log started and confirm that it doesn't show up.
Alexei Svitkine9de32cb2018-02-06 20:21:2179 SyntheticTrialGroup trial4(HashName("TestTrial3"), HashName("Group3"));
Steven Holtef58f2b22017-07-17 18:43:4580 registry.RegisterSyntheticFieldTrial(trial4);
81 registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
82 EXPECT_EQ(1U, synthetic_trials.size());
83 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
84
85 // Ensure that time has advanced by at least a tick before proceeding.
86 WaitUntilTimeChanges(base::TimeTicks::Now());
87
88 // Start a new log and ensure all three trials appear in it.
89 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
90 &synthetic_trials);
91 EXPECT_EQ(3U, synthetic_trials.size());
92 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2"));
93 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
94 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
95}
96
97TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticMultiGroupFieldTrial) {
98 SyntheticTrialRegistry registry;
99
100 // Register a synthetic trial TestTrial1 with groups A and B.
Alexei Svitkine9de32cb2018-02-06 20:21:21101 uint32_t trial_name_hash = HashName("TestTrial1");
102 std::vector<uint32_t> group_name_hashes = {HashName("A"), HashName("B")};
Steven Holtef58f2b22017-07-17 18:43:45103 registry.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
104 group_name_hashes);
105 // Ensure that time has advanced by at least a tick before proceeding.
106 WaitUntilTimeChanges(base::TimeTicks::Now());
107
108 std::vector<ActiveGroupId> synthetic_trials;
109 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
110 &synthetic_trials);
111 EXPECT_EQ(2U, synthetic_trials.size());
112 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "A"));
113 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "B"));
114
115 // Change the group for the trial to a single group.
Alexei Svitkine9de32cb2018-02-06 20:21:21116 group_name_hashes = {HashName("X")};
Steven Holtef58f2b22017-07-17 18:43:45117 registry.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
118 group_name_hashes);
119 // Ensure that time has advanced by at least a tick before proceeding.
120 WaitUntilTimeChanges(base::TimeTicks::Now());
121
122 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
123 &synthetic_trials);
124 EXPECT_EQ(1U, synthetic_trials.size());
125 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "X"));
126
127 // Register a trial with no groups, which should effectively remove the trial.
128 group_name_hashes.clear();
129 registry.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
130 group_name_hashes);
131 // Ensure that time has advanced by at least a tick before proceeding.
132 WaitUntilTimeChanges(base::TimeTicks::Now());
133
134 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
135 &synthetic_trials);
136}
137
138TEST_F(SyntheticTrialRegistryTest, GetSyntheticFieldTrialActiveGroups) {
139 SyntheticTrialRegistry registry;
140
141 // Instantiate and setup the corresponding singleton observer which tracks the
142 // creation of all SyntheticTrialGroups.
143 registry.AddSyntheticTrialObserver(
144 SyntheticTrialsActiveGroupIdProvider::GetInstance());
145
146 // Add two synthetic trials and confirm that they show up in the list.
Alexei Svitkine9de32cb2018-02-06 20:21:21147 SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
Steven Holtef58f2b22017-07-17 18:43:45148 registry.RegisterSyntheticFieldTrial(trial1);
149
Alexei Svitkine9de32cb2018-02-06 20:21:21150 SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:45151 registry.RegisterSyntheticFieldTrial(trial2);
152
153 // Ensure that time has advanced by at least a tick before proceeding.
154 WaitUntilTimeChanges(base::TimeTicks::Now());
155
156 // Now get the list of currently active groups.
157 std::vector<std::string> output;
158 GetSyntheticTrialGroupIdsAsString(&output);
159 EXPECT_EQ(2U, output.size());
160
161 std::string trial1_hash =
162 base::StringPrintf("%x-%x", trial1.id.name, trial1.id.group);
163 EXPECT_TRUE(base::ContainsValue(output, trial1_hash));
164
165 std::string trial2_hash =
166 base::StringPrintf("%x-%x", trial2.id.name, trial2.id.group);
167 EXPECT_TRUE(base::ContainsValue(output, trial2_hash));
168}
169
170} // namespace variations