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
21namespace metrics {
22
23class MetricsStateManagerTest : public testing::Test {
24 public:
25  MetricsStateManagerTest() : is_metrics_reporting_enabled_(false) {
26    MetricsService::RegisterPrefs(prefs_.registry());
27  }
28
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.
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:
57  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.
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.
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.
98TEST_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
114TEST_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
121TEST_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
129TEST_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
142TEST_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.
189TEST_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
219TEST_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