1 // Copyright 2014 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/metrics/metrics_state_manager.h"
6
7 #include <ctype.h>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "components/metrics/client_info.h"
14 #include "components/metrics/metrics_pref_names.h"
15 #include "components/metrics/metrics_service.h"
16 #include "components/metrics/metrics_switches.h"
17 #include "components/variations/caching_permuted_entropy_provider.h"
18 #include "components/variations/pref_names.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace metrics {
22
23 class MetricsStateManagerTest : public testing::Test {
24 public:
MetricsStateManagerTest()25 MetricsStateManagerTest() : is_metrics_reporting_enabled_(false) {
26 MetricsService::RegisterPrefs(prefs_.registry());
27 }
28
CreateStateManager()29 scoped_ptr<MetricsStateManager> CreateStateManager() {
30 return MetricsStateManager::Create(
31 &prefs_,
32 base::Bind(&MetricsStateManagerTest::is_metrics_reporting_enabled,
33 base::Unretained(this)),
34 base::Bind(&MetricsStateManagerTest::MockStoreClientInfoBackup,
35 base::Unretained(this)),
36 base::Bind(&MetricsStateManagerTest::LoadFakeClientInfoBackup,
37 base::Unretained(this))).Pass();
38 }
39
40 // Sets metrics reporting as enabled for testing.
EnableMetricsReporting()41 void EnableMetricsReporting() {
42 is_metrics_reporting_enabled_ = true;
43 }
44
45 protected:
46 TestingPrefServiceSimple prefs_;
47
48 // Last ClientInfo stored by the MetricsStateManager via
49 // MockStoreClientInfoBackup.
50 scoped_ptr<ClientInfo> stored_client_info_backup_;
51
52 // If set, will be returned via LoadFakeClientInfoBackup if requested by the
53 // MetricsStateManager.
54 scoped_ptr<ClientInfo> fake_client_info_backup_;
55
56 private:
is_metrics_reporting_enabled() const57 bool is_metrics_reporting_enabled() const {
58 return is_metrics_reporting_enabled_;
59 }
60
61 // Stores the |client_info| in |stored_client_info_backup_| for verification
62 // by the tests later.
MockStoreClientInfoBackup(const ClientInfo & client_info)63 void MockStoreClientInfoBackup(const ClientInfo& client_info) {
64 stored_client_info_backup_.reset(new ClientInfo);
65 stored_client_info_backup_->client_id = client_info.client_id;
66 stored_client_info_backup_->installation_date =
67 client_info.installation_date;
68 stored_client_info_backup_->reporting_enabled_date =
69 client_info.reporting_enabled_date;
70
71 // Respect the contract that storing an empty client_id voids the existing
72 // backup (required for the last section of the ForceClientIdCreation test
73 // below).
74 if (client_info.client_id.empty())
75 fake_client_info_backup_.reset();
76 }
77
78 // Hands out a copy of |fake_client_info_backup_| if it is set.
LoadFakeClientInfoBackup()79 scoped_ptr<ClientInfo> LoadFakeClientInfoBackup() {
80 if (!fake_client_info_backup_)
81 return scoped_ptr<ClientInfo>();
82
83 scoped_ptr<ClientInfo> backup_copy(new ClientInfo);
84 backup_copy->client_id = fake_client_info_backup_->client_id;
85 backup_copy->installation_date =
86 fake_client_info_backup_->installation_date;
87 backup_copy->reporting_enabled_date =
88 fake_client_info_backup_->reporting_enabled_date;
89 return backup_copy.Pass();
90 }
91
92 bool is_metrics_reporting_enabled_;
93
94 DISALLOW_COPY_AND_ASSIGN(MetricsStateManagerTest);
95 };
96
97 // Ensure the ClientId is formatted as expected.
TEST_F(MetricsStateManagerTest,ClientIdCorrectlyFormatted)98 TEST_F(MetricsStateManagerTest, ClientIdCorrectlyFormatted) {
99 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
100 state_manager->ForceClientIdCreation();
101
102 const std::string client_id = state_manager->client_id();
103 EXPECT_EQ(36U, client_id.length());
104
105 for (size_t i = 0; i < client_id.length(); ++i) {
106 char current = client_id[i];
107 if (i == 8 || i == 13 || i == 18 || i == 23)
108 EXPECT_EQ('-', current);
109 else
110 EXPECT_TRUE(isxdigit(current));
111 }
112 }
113
TEST_F(MetricsStateManagerTest,EntropySourceUsed_Low)114 TEST_F(MetricsStateManagerTest, EntropySourceUsed_Low) {
115 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
116 state_manager->CreateEntropyProvider();
117 EXPECT_EQ(MetricsStateManager::ENTROPY_SOURCE_LOW,
118 state_manager->entropy_source_returned());
119 }
120
TEST_F(MetricsStateManagerTest,EntropySourceUsed_High)121 TEST_F(MetricsStateManagerTest, EntropySourceUsed_High) {
122 EnableMetricsReporting();
123 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
124 state_manager->CreateEntropyProvider();
125 EXPECT_EQ(MetricsStateManager::ENTROPY_SOURCE_HIGH,
126 state_manager->entropy_source_returned());
127 }
128
TEST_F(MetricsStateManagerTest,LowEntropySource0NotReset)129 TEST_F(MetricsStateManagerTest, LowEntropySource0NotReset) {
130 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
131
132 // Get the low entropy source once, to initialize it.
133 state_manager->GetLowEntropySource();
134
135 // Now, set it to 0 and ensure it doesn't get reset.
136 state_manager->low_entropy_source_ = 0;
137 EXPECT_EQ(0, state_manager->GetLowEntropySource());
138 // Call it another time, just to make sure.
139 EXPECT_EQ(0, state_manager->GetLowEntropySource());
140 }
141
TEST_F(MetricsStateManagerTest,PermutedEntropyCacheClearedWhenLowEntropyReset)142 TEST_F(MetricsStateManagerTest,
143 PermutedEntropyCacheClearedWhenLowEntropyReset) {
144 const PrefService::Preference* low_entropy_pref =
145 prefs_.FindPreference(prefs::kMetricsLowEntropySource);
146 const char* kCachePrefName = prefs::kVariationsPermutedEntropyCache;
147 int low_entropy_value = -1;
148
149 // First, generate an initial low entropy source value.
150 {
151 EXPECT_TRUE(low_entropy_pref->IsDefaultValue());
152
153 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
154 state_manager->GetLowEntropySource();
155
156 EXPECT_FALSE(low_entropy_pref->IsDefaultValue());
157 EXPECT_TRUE(low_entropy_pref->GetValue()->GetAsInteger(&low_entropy_value));
158 }
159
160 // Now, set a dummy value in the permuted entropy cache pref and verify that
161 // another call to GetLowEntropySource() doesn't clobber it when
162 // --reset-variation-state wasn't specified.
163 {
164 prefs_.SetString(kCachePrefName, "test");
165
166 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
167 state_manager->GetLowEntropySource();
168
169 EXPECT_EQ("test", prefs_.GetString(kCachePrefName));
170 EXPECT_EQ(low_entropy_value,
171 prefs_.GetInteger(prefs::kMetricsLowEntropySource));
172 }
173
174 // Verify that the cache does get reset if --reset-variations-state is passed.
175 {
176 CommandLine::ForCurrentProcess()->AppendSwitch(
177 switches::kResetVariationState);
178
179 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
180 state_manager->GetLowEntropySource();
181
182 EXPECT_TRUE(prefs_.GetString(kCachePrefName).empty());
183 }
184 }
185
186 // Check that setting the kMetricsResetIds pref to true causes the client id to
187 // be reset. We do not check that the low entropy source is reset because we
188 // cannot ensure that metrics state manager won't generate the same id again.
TEST_F(MetricsStateManagerTest,ResetMetricsIDs)189 TEST_F(MetricsStateManagerTest, ResetMetricsIDs) {
190 // Set an initial client id in prefs. It should not be possible for the
191 // metrics state manager to generate this id randomly.
192 const std::string kInitialClientId = "initial client id";
193 prefs_.SetString(prefs::kMetricsClientID, kInitialClientId);
194
195 // Make sure the initial client id isn't reset by the metrics state manager.
196 {
197 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
198 state_manager->ForceClientIdCreation();
199 EXPECT_EQ(kInitialClientId, state_manager->client_id());
200 }
201
202 // Set the reset pref to cause the IDs to be reset.
203 prefs_.SetBoolean(prefs::kMetricsResetIds, true);
204
205 // Cause the actual reset to happen.
206 {
207 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
208 state_manager->ForceClientIdCreation();
209 EXPECT_NE(kInitialClientId, state_manager->client_id());
210
211 state_manager->GetLowEntropySource();
212
213 EXPECT_FALSE(prefs_.GetBoolean(prefs::kMetricsResetIds));
214 }
215
216 EXPECT_NE(kInitialClientId, prefs_.GetString(prefs::kMetricsClientID));
217 }
218
TEST_F(MetricsStateManagerTest,ForceClientIdCreation)219 TEST_F(MetricsStateManagerTest, ForceClientIdCreation) {
220 const int64 kFakeInstallationDate = 12345;
221 prefs_.SetInt64(prefs::kInstallDate, kFakeInstallationDate);
222
223 const int64 test_begin_time = base::Time::Now().ToTimeT();
224
225 // Holds ClientInfo from previous scoped test for extra checks.
226 scoped_ptr<ClientInfo> previous_client_info;
227
228 {
229 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
230
231 // client_id shouldn't be auto-generated if metrics reporting is not
232 // enabled.
233 EXPECT_EQ(std::string(), state_manager->client_id());
234 EXPECT_EQ(0, prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp));
235
236 // Confirm that the initial ForceClientIdCreation call creates the client id
237 // and backs it up via MockStoreClientInfoBackup.
238 EXPECT_FALSE(stored_client_info_backup_);
239 state_manager->ForceClientIdCreation();
240 EXPECT_NE(std::string(), state_manager->client_id());
241 EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
242 test_begin_time);
243
244 ASSERT_TRUE(stored_client_info_backup_);
245 EXPECT_EQ(state_manager->client_id(),
246 stored_client_info_backup_->client_id);
247 EXPECT_EQ(kFakeInstallationDate,
248 stored_client_info_backup_->installation_date);
249 EXPECT_EQ(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
250 stored_client_info_backup_->reporting_enabled_date);
251
252 previous_client_info = stored_client_info_backup_.Pass();
253 }
254
255 EnableMetricsReporting();
256
257 {
258 EXPECT_FALSE(stored_client_info_backup_);
259
260 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
261
262 // client_id should be auto-obtained from the constructor when metrics
263 // reporting is enabled.
264 EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
265
266 // The backup should also be refreshed when the client id re-initialized.
267 ASSERT_TRUE(stored_client_info_backup_);
268 EXPECT_EQ(previous_client_info->client_id,
269 stored_client_info_backup_->client_id);
270 EXPECT_EQ(kFakeInstallationDate,
271 stored_client_info_backup_->installation_date);
272 EXPECT_EQ(previous_client_info->reporting_enabled_date,
273 stored_client_info_backup_->reporting_enabled_date);
274
275 // Re-forcing client id creation shouldn't cause another backup and
276 // shouldn't affect the existing client id.
277 stored_client_info_backup_.reset();
278 state_manager->ForceClientIdCreation();
279 EXPECT_FALSE(stored_client_info_backup_);
280 EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
281 }
282
283 const int64 kBackupInstallationDate = 1111;
284 const int64 kBackupReportingEnabledDate = 2222;
285 const char kBackupClientId[] = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
286 fake_client_info_backup_.reset(new ClientInfo);
287 fake_client_info_backup_->client_id = kBackupClientId;
288 fake_client_info_backup_->installation_date = kBackupInstallationDate;
289 fake_client_info_backup_->reporting_enabled_date =
290 kBackupReportingEnabledDate;
291
292 {
293 // The existence of a backup should result in the same behaviour as
294 // before if we already have a client id.
295
296 EXPECT_FALSE(stored_client_info_backup_);
297
298 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
299 EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
300
301 // The backup should also be refreshed when the client id re-initialized.
302 ASSERT_TRUE(stored_client_info_backup_);
303 EXPECT_EQ(previous_client_info->client_id,
304 stored_client_info_backup_->client_id);
305 EXPECT_EQ(kFakeInstallationDate,
306 stored_client_info_backup_->installation_date);
307 EXPECT_EQ(previous_client_info->reporting_enabled_date,
308 stored_client_info_backup_->reporting_enabled_date);
309 stored_client_info_backup_.reset();
310 }
311
312 prefs_.ClearPref(prefs::kMetricsClientID);
313 prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp);
314
315 {
316 // The backup should kick in if the client id has gone missing. It should
317 // replace remaining and missing dates as well.
318
319 EXPECT_FALSE(stored_client_info_backup_);
320
321 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
322 EXPECT_EQ(kBackupClientId, state_manager->client_id());
323 EXPECT_EQ(kBackupInstallationDate, prefs_.GetInt64(prefs::kInstallDate));
324 EXPECT_EQ(kBackupReportingEnabledDate,
325 prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp));
326
327 EXPECT_TRUE(stored_client_info_backup_);
328 stored_client_info_backup_.reset();
329 }
330
331 const char kNoDashesBackupClientId[] = "AAAAAAAABBBBCCCCDDDDEEEEEEEEEEEE";
332 fake_client_info_backup_.reset(new ClientInfo);
333 fake_client_info_backup_->client_id = kNoDashesBackupClientId;
334
335 prefs_.ClearPref(prefs::kInstallDate);
336 prefs_.ClearPref(prefs::kMetricsClientID);
337 prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp);
338
339 {
340 // When running the backup from old-style client ids, dashes should be
341 // re-added. And missing dates in backup should be replaced by Time::Now().
342
343 EXPECT_FALSE(stored_client_info_backup_);
344
345 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
346 EXPECT_EQ(kBackupClientId, state_manager->client_id());
347 EXPECT_GE(prefs_.GetInt64(prefs::kInstallDate), test_begin_time);
348 EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
349 test_begin_time);
350
351 EXPECT_TRUE(stored_client_info_backup_);
352 previous_client_info = stored_client_info_backup_.Pass();
353 }
354
355 prefs_.SetBoolean(prefs::kMetricsResetIds, true);
356
357 {
358 // Upon request to reset metrics ids, the existing backup should not be
359 // restored.
360
361 EXPECT_FALSE(stored_client_info_backup_);
362
363 scoped_ptr<MetricsStateManager> state_manager(CreateStateManager());
364
365 // A brand new client id should have been generated.
366 EXPECT_NE(std::string(), state_manager->client_id());
367 EXPECT_NE(previous_client_info->client_id, state_manager->client_id());
368
369 // The installation date should not have been affected.
370 EXPECT_EQ(previous_client_info->installation_date,
371 prefs_.GetInt64(prefs::kInstallDate));
372
373 // The metrics-reporting-enabled date will be reset to Now().
374 EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
375 previous_client_info->reporting_enabled_date);
376
377 stored_client_info_backup_.reset();
378 }
379 }
380
381 } // namespace metrics
382