blob: d9623fb01777470e90438dd2e277c920a4dd9649 [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
Alexei Svitkinee726dd522018-03-09 04:41:037#include <string>
8
9#include "base/metrics/field_trial.h"
Steven Holtef58f2b22017-07-17 18:43:4510#include "base/strings/stringprintf.h"
11#include "components/variations/active_field_trials.h"
Alexei Svitkine9de32cb2018-02-06 20:21:2112#include "components/variations/hashing.h"
Steven Holtef58f2b22017-07-17 18:43:4513#include "components/variations/synthetic_trials_active_group_id_provider.h"
Alexei Svitkinee726dd522018-03-09 04:41:0314#include "components/variations/variations_crash_keys.h"
Steven Holtef58f2b22017-07-17 18:43:4515#include "testing/gtest/include/gtest/gtest.h"
16
17namespace variations {
18
19namespace {
20
21class SyntheticTrialRegistryTest : public ::testing::Test {
22 public:
Alexei Svitkinee726dd522018-03-09 04:41:0323 SyntheticTrialRegistryTest() : field_trial_list_(nullptr) { InitCrashKeys(); }
24 ~SyntheticTrialRegistryTest() override { ClearCrashKeysInstanceForTesting(); }
25
Steven Holtef58f2b22017-07-17 18:43:4526 // Returns true if there is a synthetic trial in the given vector that matches
27 // the given trial name and trial group; returns false otherwise.
28 bool HasSyntheticTrial(const std::vector<ActiveGroupId>& synthetic_trials,
29 const std::string& trial_name,
30 const std::string& trial_group) {
Alexei Svitkine9de32cb2018-02-06 20:21:2131 uint32_t trial_name_hash = HashName(trial_name);
32 uint32_t trial_group_hash = HashName(trial_group);
Steven Holtef58f2b22017-07-17 18:43:4533 for (const ActiveGroupId& trial : synthetic_trials) {
34 if (trial.name == trial_name_hash && trial.group == trial_group_hash)
35 return true;
36 }
37 return false;
38 }
39
40 // Waits until base::TimeTicks::Now() no longer equals |value|. This should
41 // take between 1-15ms per the documented resolution of base::TimeTicks.
42 void WaitUntilTimeChanges(const base::TimeTicks& value) {
43 while (base::TimeTicks::Now() == value) {
44 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
45 }
46 }
Alexei Svitkinee726dd522018-03-09 04:41:0347
48 private:
49 base::FieldTrialList field_trial_list_;
50
51 DISALLOW_COPY_AND_ASSIGN(SyntheticTrialRegistryTest);
Steven Holtef58f2b22017-07-17 18:43:4552};
53
54} // namespace
55
56TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticTrial) {
57 SyntheticTrialRegistry registry;
58
59 // Add two synthetic trials and confirm that they show up in the list.
Alexei Svitkine9de32cb2018-02-06 20:21:2160 SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
Steven Holtef58f2b22017-07-17 18:43:4561 registry.RegisterSyntheticFieldTrial(trial1);
62
Alexei Svitkine9de32cb2018-02-06 20:21:2163 SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:4564 registry.RegisterSyntheticFieldTrial(trial2);
65 // Ensure that time has advanced by at least a tick before proceeding.
66 WaitUntilTimeChanges(base::TimeTicks::Now());
67
68 // Save the time when the log was started (it's okay for this to be greater
69 // than the time recorded by the above call since it's used to ensure the
70 // value changes).
71 const base::TimeTicks begin_log_time = base::TimeTicks::Now();
72
73 std::vector<ActiveGroupId> synthetic_trials;
74 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
75 &synthetic_trials);
76 EXPECT_EQ(2U, synthetic_trials.size());
77 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1"));
78 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
79
80 // Ensure that time has advanced by at least a tick before proceeding.
81 WaitUntilTimeChanges(begin_log_time);
82
83 // Change the group for the first trial after the log started.
Alexei Svitkine9de32cb2018-02-06 20:21:2184 SyntheticTrialGroup trial3(HashName("TestTrial1"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:4585 registry.RegisterSyntheticFieldTrial(trial3);
86 registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
87 EXPECT_EQ(1U, synthetic_trials.size());
88 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
89
90 // Add a new trial after the log started and confirm that it doesn't show up.
Alexei Svitkine9de32cb2018-02-06 20:21:2191 SyntheticTrialGroup trial4(HashName("TestTrial3"), HashName("Group3"));
Steven Holtef58f2b22017-07-17 18:43:4592 registry.RegisterSyntheticFieldTrial(trial4);
93 registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
94 EXPECT_EQ(1U, synthetic_trials.size());
95 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
96
97 // Ensure that time has advanced by at least a tick before proceeding.
98 WaitUntilTimeChanges(base::TimeTicks::Now());
99
100 // Start a new log and ensure all three trials appear in it.
101 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
102 &synthetic_trials);
103 EXPECT_EQ(3U, synthetic_trials.size());
104 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2"));
105 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
106 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
107}
108
109TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticMultiGroupFieldTrial) {
110 SyntheticTrialRegistry registry;
111
112 // Register a synthetic trial TestTrial1 with groups A and B.
Alexei Svitkine9de32cb2018-02-06 20:21:21113 uint32_t trial_name_hash = HashName("TestTrial1");
114 std::vector<uint32_t> group_name_hashes = {HashName("A"), HashName("B")};
Steven Holtef58f2b22017-07-17 18:43:45115 registry.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
116 group_name_hashes);
117 // Ensure that time has advanced by at least a tick before proceeding.
118 WaitUntilTimeChanges(base::TimeTicks::Now());
119
120 std::vector<ActiveGroupId> synthetic_trials;
121 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
122 &synthetic_trials);
123 EXPECT_EQ(2U, synthetic_trials.size());
124 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "A"));
125 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "B"));
126
127 // Change the group for the trial to a single group.
Alexei Svitkine9de32cb2018-02-06 20:21:21128 group_name_hashes = {HashName("X")};
Steven Holtef58f2b22017-07-17 18:43:45129 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 EXPECT_EQ(1U, synthetic_trials.size());
137 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "X"));
138
139 // Register a trial with no groups, which should effectively remove the trial.
140 group_name_hashes.clear();
141 registry.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
142 group_name_hashes);
143 // Ensure that time has advanced by at least a tick before proceeding.
144 WaitUntilTimeChanges(base::TimeTicks::Now());
145
146 registry.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
147 &synthetic_trials);
148}
149
150TEST_F(SyntheticTrialRegistryTest, GetSyntheticFieldTrialActiveGroups) {
151 SyntheticTrialRegistry registry;
152
153 // Instantiate and setup the corresponding singleton observer which tracks the
154 // creation of all SyntheticTrialGroups.
155 registry.AddSyntheticTrialObserver(
156 SyntheticTrialsActiveGroupIdProvider::GetInstance());
157
158 // Add two synthetic trials and confirm that they show up in the list.
Alexei Svitkine9de32cb2018-02-06 20:21:21159 SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
Steven Holtef58f2b22017-07-17 18:43:45160 registry.RegisterSyntheticFieldTrial(trial1);
161
Alexei Svitkine9de32cb2018-02-06 20:21:21162 SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
Steven Holtef58f2b22017-07-17 18:43:45163 registry.RegisterSyntheticFieldTrial(trial2);
164
165 // Ensure that time has advanced by at least a tick before proceeding.
166 WaitUntilTimeChanges(base::TimeTicks::Now());
167
168 // Now get the list of currently active groups.
169 std::vector<std::string> output;
170 GetSyntheticTrialGroupIdsAsString(&output);
171 EXPECT_EQ(2U, output.size());
172
173 std::string trial1_hash =
174 base::StringPrintf("%x-%x", trial1.id.name, trial1.id.group);
175 EXPECT_TRUE(base::ContainsValue(output, trial1_hash));
176
177 std::string trial2_hash =
178 base::StringPrintf("%x-%x", trial2.id.name, trial2.id.group);
179 EXPECT_TRUE(base::ContainsValue(output, trial2_hash));
180}
181
182} // namespace variations