• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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