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.
5 #include "components/metrics/metrics_service.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/statistics_recorder.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "base/threading/platform_thread.h"
15 #include "components/compression/compression_utils.h"
16 #include "components/metrics/client_info.h"
17 #include "components/metrics/metrics_hashes.h"
18 #include "components/metrics/metrics_log.h"
19 #include "components/metrics/metrics_pref_names.h"
20 #include "components/metrics/metrics_state_manager.h"
21 #include "components/metrics/test_metrics_provider.h"
22 #include "components/metrics/test_metrics_service_client.h"
23 #include "components/variations/metrics_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
30 void StoreNoClientInfoBackup(const ClientInfo
& /* client_info */) {
33 scoped_ptr
<ClientInfo
> ReturnNoBackup() {
34 return scoped_ptr
<ClientInfo
>();
37 class TestMetricsService
: public MetricsService
{
39 TestMetricsService(MetricsStateManager
* state_manager
,
40 MetricsServiceClient
* client
,
41 PrefService
* local_state
)
42 : MetricsService(state_manager
, client
, local_state
) {}
43 ~TestMetricsService() override
{}
45 using MetricsService::log_manager
;
48 DISALLOW_COPY_AND_ASSIGN(TestMetricsService
);
51 class TestMetricsLog
: public MetricsLog
{
53 TestMetricsLog(const std::string
& client_id
,
55 MetricsServiceClient
* client
,
56 PrefService
* local_state
)
57 : MetricsLog(client_id
,
59 MetricsLog::ONGOING_LOG
,
63 ~TestMetricsLog() override
{}
66 DISALLOW_COPY_AND_ASSIGN(TestMetricsLog
);
69 class MetricsServiceTest
: public testing::Test
{
71 MetricsServiceTest() : is_metrics_reporting_enabled_(false) {
72 MetricsService::RegisterPrefs(testing_local_state_
.registry());
73 metrics_state_manager_
= MetricsStateManager::Create(
75 base::Bind(&MetricsServiceTest::is_metrics_reporting_enabled
,
76 base::Unretained(this)),
77 base::Bind(&StoreNoClientInfoBackup
),
78 base::Bind(&ReturnNoBackup
));
81 ~MetricsServiceTest() override
{
82 MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE
,
86 MetricsStateManager
* GetMetricsStateManager() {
87 return metrics_state_manager_
.get();
90 PrefService
* GetLocalState() { return &testing_local_state_
; }
92 // Sets metrics reporting as enabled for testing.
93 void EnableMetricsReporting() {
94 is_metrics_reporting_enabled_
= true;
97 // Waits until base::TimeTicks::Now() no longer equals |value|. This should
98 // take between 1-15ms per the documented resolution of base::TimeTicks.
99 void WaitUntilTimeChanges(const base::TimeTicks
& value
) {
100 while (base::TimeTicks::Now() == value
) {
101 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
105 // Returns true if there is a synthetic trial in the given vector that matches
106 // the given trial name and trial group; returns false otherwise.
107 bool HasSyntheticTrial(
108 const std::vector
<variations::ActiveGroupId
>& synthetic_trials
,
109 const std::string
& trial_name
,
110 const std::string
& trial_group
) {
111 uint32 trial_name_hash
= HashName(trial_name
);
112 uint32 trial_group_hash
= HashName(trial_group
);
113 for (const variations::ActiveGroupId
& trial
: synthetic_trials
) {
114 if (trial
.name
== trial_name_hash
&& trial
.group
== trial_group_hash
)
120 // Finds a histogram with the specified |name_hash| in |histograms|.
121 const base::HistogramBase
* FindHistogram(
122 const base::StatisticsRecorder::Histograms
& histograms
,
124 for (const base::HistogramBase
* histogram
: histograms
) {
125 if (name_hash
== HashMetricName(histogram
->histogram_name()))
131 // Checks whether |uma_log| contains any histograms that are not flagged
132 // with kUmaStabilityHistogramFlag. Stability logs should only contain such
134 void CheckForNonStabilityHistograms(
135 const ChromeUserMetricsExtension
& uma_log
) {
136 const int kStabilityFlags
= base::HistogramBase::kUmaStabilityHistogramFlag
;
137 base::StatisticsRecorder::Histograms histograms
;
138 base::StatisticsRecorder::GetHistograms(&histograms
);
139 for (int i
= 0; i
< uma_log
.histogram_event_size(); ++i
) {
140 const uint64 hash
= uma_log
.histogram_event(i
).name_hash();
142 const base::HistogramBase
* histogram
= FindHistogram(histograms
, hash
);
143 EXPECT_TRUE(histogram
) << hash
;
145 EXPECT_EQ(kStabilityFlags
, histogram
->flags() & kStabilityFlags
) << hash
;
150 bool is_metrics_reporting_enabled() const {
151 return is_metrics_reporting_enabled_
;
154 bool is_metrics_reporting_enabled_
;
155 TestingPrefServiceSimple testing_local_state_
;
156 scoped_ptr
<MetricsStateManager
> metrics_state_manager_
;
157 base::MessageLoop message_loop
;
159 DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest
);
164 TEST_F(MetricsServiceTest
, InitialStabilityLogAfterCleanShutDown
) {
165 EnableMetricsReporting();
166 GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly
, true);
168 TestMetricsServiceClient client
;
169 TestMetricsService
service(
170 GetMetricsStateManager(), &client
, GetLocalState());
172 TestMetricsProvider
* test_provider
= new TestMetricsProvider();
173 service
.RegisterMetricsProvider(scoped_ptr
<MetricsProvider
>(test_provider
));
175 service
.InitializeMetricsRecordingState();
176 // No initial stability log should be generated.
177 EXPECT_FALSE(service
.log_manager()->has_unsent_logs());
178 EXPECT_FALSE(service
.log_manager()->has_staged_log());
180 // The test provider should not have been called upon to provide initial
181 // stability nor regular stability metrics.
182 EXPECT_FALSE(test_provider
->provide_initial_stability_metrics_called());
183 EXPECT_FALSE(test_provider
->provide_stability_metrics_called());
186 TEST_F(MetricsServiceTest
, InitialStabilityLogAtProviderRequest
) {
187 EnableMetricsReporting();
189 // Save an existing system profile to prefs, to correspond to what would be
190 // saved from a previous session.
191 TestMetricsServiceClient client
;
192 TestMetricsLog
log("client", 1, &client
, GetLocalState());
193 log
.RecordEnvironment(std::vector
<MetricsProvider
*>(),
194 std::vector
<variations::ActiveGroupId
>(), 0, 0);
196 // Record stability build time and version from previous session, so that
197 // stability metrics (including exited cleanly flag) won't be cleared.
198 GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime
,
199 MetricsLog::GetBuildTime());
200 GetLocalState()->SetString(prefs::kStabilityStatsVersion
,
201 client
.GetVersionString());
203 // Set the clean exit flag, as that will otherwise cause a stabilty
204 // log to be produced, irrespective provider requests.
205 GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly
, true);
207 TestMetricsService
service(
208 GetMetricsStateManager(), &client
, GetLocalState());
209 // Add a metrics provider that requests a stability log.
210 TestMetricsProvider
* test_provider
= new TestMetricsProvider();
211 test_provider
->set_has_initial_stability_metrics(true);
212 service
.RegisterMetricsProvider(
213 scoped_ptr
<MetricsProvider
>(test_provider
));
215 service
.InitializeMetricsRecordingState();
217 // The initial stability log should be generated and persisted in unsent logs.
218 MetricsLogManager
* log_manager
= service
.log_manager();
219 EXPECT_TRUE(log_manager
->has_unsent_logs());
220 EXPECT_FALSE(log_manager
->has_staged_log());
222 // The test provider should have been called upon to provide initial
223 // stability and regular stability metrics.
224 EXPECT_TRUE(test_provider
->provide_initial_stability_metrics_called());
225 EXPECT_TRUE(test_provider
->provide_stability_metrics_called());
227 // Stage the log and retrieve it.
228 log_manager
->StageNextLogForUpload();
229 EXPECT_TRUE(log_manager
->has_staged_log());
231 std::string uncompressed_log
;
232 EXPECT_TRUE(compression::GzipUncompress(log_manager
->staged_log(),
235 ChromeUserMetricsExtension uma_log
;
236 EXPECT_TRUE(uma_log
.ParseFromString(uncompressed_log
));
238 EXPECT_TRUE(uma_log
.has_client_id());
239 EXPECT_TRUE(uma_log
.has_session_id());
240 EXPECT_TRUE(uma_log
.has_system_profile());
241 EXPECT_EQ(0, uma_log
.user_action_event_size());
242 EXPECT_EQ(0, uma_log
.omnibox_event_size());
243 EXPECT_EQ(0, uma_log
.profiler_event_size());
244 EXPECT_EQ(0, uma_log
.perf_data_size());
245 CheckForNonStabilityHistograms(uma_log
);
247 // As there wasn't an unclean shutdown, this log has zero crash count.
248 EXPECT_EQ(0, uma_log
.system_profile().stability().crash_count());
251 TEST_F(MetricsServiceTest
, InitialStabilityLogAfterCrash
) {
252 EnableMetricsReporting();
253 GetLocalState()->ClearPref(prefs::kStabilityExitedCleanly
);
255 // Set up prefs to simulate restarting after a crash.
257 // Save an existing system profile to prefs, to correspond to what would be
258 // saved from a previous session.
259 TestMetricsServiceClient client
;
260 TestMetricsLog
log("client", 1, &client
, GetLocalState());
261 log
.RecordEnvironment(std::vector
<MetricsProvider
*>(),
262 std::vector
<variations::ActiveGroupId
>(), 0, 0);
264 // Record stability build time and version from previous session, so that
265 // stability metrics (including exited cleanly flag) won't be cleared.
266 GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime
,
267 MetricsLog::GetBuildTime());
268 GetLocalState()->SetString(prefs::kStabilityStatsVersion
,
269 client
.GetVersionString());
271 GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly
, false);
273 TestMetricsService
service(
274 GetMetricsStateManager(), &client
, GetLocalState());
276 TestMetricsProvider
* test_provider
= new TestMetricsProvider();
277 service
.RegisterMetricsProvider(scoped_ptr
<MetricsProvider
>(test_provider
));
278 service
.InitializeMetricsRecordingState();
280 // The initial stability log should be generated and persisted in unsent logs.
281 MetricsLogManager
* log_manager
= service
.log_manager();
282 EXPECT_TRUE(log_manager
->has_unsent_logs());
283 EXPECT_FALSE(log_manager
->has_staged_log());
285 // The test provider should have been called upon to provide initial
286 // stability and regular stability metrics.
287 EXPECT_TRUE(test_provider
->provide_initial_stability_metrics_called());
288 EXPECT_TRUE(test_provider
->provide_stability_metrics_called());
290 // Stage the log and retrieve it.
291 log_manager
->StageNextLogForUpload();
292 EXPECT_TRUE(log_manager
->has_staged_log());
294 std::string uncompressed_log
;
295 EXPECT_TRUE(compression::GzipUncompress(log_manager
->staged_log(),
298 ChromeUserMetricsExtension uma_log
;
299 EXPECT_TRUE(uma_log
.ParseFromString(uncompressed_log
));
301 EXPECT_TRUE(uma_log
.has_client_id());
302 EXPECT_TRUE(uma_log
.has_session_id());
303 EXPECT_TRUE(uma_log
.has_system_profile());
304 EXPECT_EQ(0, uma_log
.user_action_event_size());
305 EXPECT_EQ(0, uma_log
.omnibox_event_size());
306 EXPECT_EQ(0, uma_log
.profiler_event_size());
307 EXPECT_EQ(0, uma_log
.perf_data_size());
308 CheckForNonStabilityHistograms(uma_log
);
310 EXPECT_EQ(1, uma_log
.system_profile().stability().crash_count());
313 TEST_F(MetricsServiceTest
, RegisterSyntheticTrial
) {
314 TestMetricsServiceClient client
;
315 MetricsService
service(GetMetricsStateManager(), &client
, GetLocalState());
317 // Add two synthetic trials and confirm that they show up in the list.
318 SyntheticTrialGroup
trial1(HashName("TestTrial1"), HashName("Group1"));
319 service
.RegisterSyntheticFieldTrial(trial1
);
321 SyntheticTrialGroup
trial2(HashName("TestTrial2"), HashName("Group2"));
322 service
.RegisterSyntheticFieldTrial(trial2
);
323 // Ensure that time has advanced by at least a tick before proceeding.
324 WaitUntilTimeChanges(base::TimeTicks::Now());
326 service
.log_manager_
.BeginLoggingWithLog(scoped_ptr
<MetricsLog
>(
327 new MetricsLog("clientID",
329 MetricsLog::INITIAL_STABILITY_LOG
,
332 // Save the time when the log was started (it's okay for this to be greater
333 // than the time recorded by the above call since it's used to ensure the
335 const base::TimeTicks begin_log_time
= base::TimeTicks::Now();
337 std::vector
<variations::ActiveGroupId
> synthetic_trials
;
338 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
339 EXPECT_EQ(2U, synthetic_trials
.size());
340 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial1", "Group1"));
341 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
343 // Ensure that time has advanced by at least a tick before proceeding.
344 WaitUntilTimeChanges(begin_log_time
);
346 // Change the group for the first trial after the log started.
347 SyntheticTrialGroup
trial3(HashName("TestTrial1"), HashName("Group2"));
348 service
.RegisterSyntheticFieldTrial(trial3
);
349 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
350 EXPECT_EQ(1U, synthetic_trials
.size());
351 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
353 // Add a new trial after the log started and confirm that it doesn't show up.
354 SyntheticTrialGroup
trial4(HashName("TestTrial3"), HashName("Group3"));
355 service
.RegisterSyntheticFieldTrial(trial4
);
356 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
357 EXPECT_EQ(1U, synthetic_trials
.size());
358 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
360 // Ensure that time has advanced by at least a tick before proceeding.
361 WaitUntilTimeChanges(base::TimeTicks::Now());
363 // Start a new log and ensure all three trials appear in it.
364 service
.log_manager_
.FinishCurrentLog();
365 service
.log_manager_
.BeginLoggingWithLog(
366 scoped_ptr
<MetricsLog
>(new MetricsLog(
367 "clientID", 1, MetricsLog::ONGOING_LOG
, &client
, GetLocalState())));
368 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
369 EXPECT_EQ(3U, synthetic_trials
.size());
370 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial1", "Group2"));
371 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
372 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial3", "Group3"));
373 service
.log_manager_
.FinishCurrentLog();
376 TEST_F(MetricsServiceTest
,
377 MetricsProviderOnRecordingDisabledCalledOnInitialStop
) {
378 TestMetricsServiceClient client
;
379 TestMetricsService
service(
380 GetMetricsStateManager(), &client
, GetLocalState());
382 TestMetricsProvider
* test_provider
= new TestMetricsProvider();
383 service
.RegisterMetricsProvider(scoped_ptr
<MetricsProvider
>(test_provider
));
385 service
.InitializeMetricsRecordingState();
388 EXPECT_TRUE(test_provider
->on_recording_disabled_called());
391 } // namespace metrics