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/prefs/testing_pref_service.h"
13 #include "base/threading/platform_thread.h"
14 #include "components/metrics/client_info.h"
15 #include "components/metrics/compression_utils.h"
16 #include "components/metrics/metrics_log.h"
17 #include "components/metrics/metrics_pref_names.h"
18 #include "components/metrics/metrics_service_observer.h"
19 #include "components/metrics/metrics_state_manager.h"
20 #include "components/metrics/test_metrics_service_client.h"
21 #include "components/variations/metrics_util.h"
22 #include "testing/gtest/include/gtest/gtest.h"
28 void StoreNoClientInfoBackup(const ClientInfo
& /* client_info */) {
31 scoped_ptr
<ClientInfo
> ReturnNoBackup() {
32 return scoped_ptr
<ClientInfo
>();
35 class TestMetricsService
: public MetricsService
{
37 TestMetricsService(MetricsStateManager
* state_manager
,
38 MetricsServiceClient
* client
,
39 PrefService
* local_state
)
40 : MetricsService(state_manager
, client
, local_state
) {}
41 virtual ~TestMetricsService() {}
43 using MetricsService::log_manager
;
46 DISALLOW_COPY_AND_ASSIGN(TestMetricsService
);
49 class TestMetricsLog
: public MetricsLog
{
51 TestMetricsLog(const std::string
& client_id
,
53 MetricsServiceClient
* client
,
54 PrefService
* local_state
)
55 : MetricsLog(client_id
,
57 MetricsLog::ONGOING_LOG
,
61 virtual ~TestMetricsLog() {}
64 DISALLOW_COPY_AND_ASSIGN(TestMetricsLog
);
67 class MetricsServiceTest
: public testing::Test
{
69 MetricsServiceTest() : is_metrics_reporting_enabled_(false) {
70 MetricsService::RegisterPrefs(testing_local_state_
.registry());
71 metrics_state_manager_
= MetricsStateManager::Create(
73 base::Bind(&MetricsServiceTest::is_metrics_reporting_enabled
,
74 base::Unretained(this)),
75 base::Bind(&StoreNoClientInfoBackup
),
76 base::Bind(&ReturnNoBackup
));
79 virtual ~MetricsServiceTest() {
80 MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE
,
84 MetricsStateManager
* GetMetricsStateManager() {
85 return metrics_state_manager_
.get();
88 PrefService
* GetLocalState() { return &testing_local_state_
; }
90 // Sets metrics reporting as enabled for testing.
91 void EnableMetricsReporting() {
92 is_metrics_reporting_enabled_
= true;
95 // Waits until base::TimeTicks::Now() no longer equals |value|. This should
96 // take between 1-15ms per the documented resolution of base::TimeTicks.
97 void WaitUntilTimeChanges(const base::TimeTicks
& value
) {
98 while (base::TimeTicks::Now() == value
) {
99 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
103 // Returns true if there is a synthetic trial in the given vector that matches
104 // the given trial name and trial group; returns false otherwise.
105 bool HasSyntheticTrial(
106 const std::vector
<variations::ActiveGroupId
>& synthetic_trials
,
107 const std::string
& trial_name
,
108 const std::string
& trial_group
) {
109 uint32 trial_name_hash
= HashName(trial_name
);
110 uint32 trial_group_hash
= HashName(trial_group
);
111 for (std::vector
<variations::ActiveGroupId
>::const_iterator it
=
112 synthetic_trials
.begin();
113 it
!= synthetic_trials
.end(); ++it
) {
114 if ((*it
).name
== trial_name_hash
&& (*it
).group
== trial_group_hash
)
121 bool is_metrics_reporting_enabled() const {
122 return is_metrics_reporting_enabled_
;
125 bool is_metrics_reporting_enabled_
;
126 TestingPrefServiceSimple testing_local_state_
;
127 scoped_ptr
<MetricsStateManager
> metrics_state_manager_
;
128 base::MessageLoop message_loop
;
130 DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest
);
133 class TestMetricsServiceObserver
: public MetricsServiceObserver
{
135 TestMetricsServiceObserver(): observed_(0) {}
136 virtual ~TestMetricsServiceObserver() {}
138 virtual void OnDidCreateMetricsLog() OVERRIDE
{
141 int observed() const { return observed_
; }
146 DISALLOW_COPY_AND_ASSIGN(TestMetricsServiceObserver
);
151 TEST_F(MetricsServiceTest
, InitialStabilityLogAfterCleanShutDown
) {
152 EnableMetricsReporting();
153 GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly
, true);
155 TestMetricsServiceClient client
;
156 TestMetricsService
service(
157 GetMetricsStateManager(), &client
, GetLocalState());
158 service
.InitializeMetricsRecordingState();
159 // No initial stability log should be generated.
160 EXPECT_FALSE(service
.log_manager()->has_unsent_logs());
161 EXPECT_FALSE(service
.log_manager()->has_staged_log());
164 TEST_F(MetricsServiceTest
, InitialStabilityLogAfterCrash
) {
165 EnableMetricsReporting();
166 GetLocalState()->ClearPref(prefs::kStabilityExitedCleanly
);
168 // Set up prefs to simulate restarting after a crash.
170 // Save an existing system profile to prefs, to correspond to what would be
171 // saved from a previous session.
172 TestMetricsServiceClient client
;
173 TestMetricsLog
log("client", 1, &client
, GetLocalState());
174 log
.RecordEnvironment(std::vector
<MetricsProvider
*>(),
175 std::vector
<variations::ActiveGroupId
>(),
178 // Record stability build time and version from previous session, so that
179 // stability metrics (including exited cleanly flag) won't be cleared.
180 GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime
,
181 MetricsLog::GetBuildTime());
182 GetLocalState()->SetString(prefs::kStabilityStatsVersion
,
183 client
.GetVersionString());
185 GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly
, false);
187 TestMetricsService
service(
188 GetMetricsStateManager(), &client
, GetLocalState());
189 service
.InitializeMetricsRecordingState();
191 // The initial stability log should be generated and persisted in unsent logs.
192 MetricsLogManager
* log_manager
= service
.log_manager();
193 EXPECT_TRUE(log_manager
->has_unsent_logs());
194 EXPECT_FALSE(log_manager
->has_staged_log());
196 // Stage the log and retrieve it.
197 log_manager
->StageNextLogForUpload();
198 EXPECT_TRUE(log_manager
->has_staged_log());
200 std::string uncompressed_log
;
201 EXPECT_TRUE(metrics::GzipUncompress(log_manager
->staged_log(),
204 metrics::ChromeUserMetricsExtension uma_log
;
205 EXPECT_TRUE(uma_log
.ParseFromString(uncompressed_log
));
207 EXPECT_TRUE(uma_log
.has_client_id());
208 EXPECT_TRUE(uma_log
.has_session_id());
209 EXPECT_TRUE(uma_log
.has_system_profile());
210 EXPECT_EQ(0, uma_log
.user_action_event_size());
211 EXPECT_EQ(0, uma_log
.omnibox_event_size());
212 EXPECT_EQ(0, uma_log
.histogram_event_size());
213 EXPECT_EQ(0, uma_log
.profiler_event_size());
214 EXPECT_EQ(0, uma_log
.perf_data_size());
216 EXPECT_EQ(1, uma_log
.system_profile().stability().crash_count());
219 TEST_F(MetricsServiceTest
, RegisterSyntheticTrial
) {
220 metrics::TestMetricsServiceClient client
;
221 MetricsService
service(GetMetricsStateManager(), &client
, GetLocalState());
223 // Add two synthetic trials and confirm that they show up in the list.
224 SyntheticTrialGroup
trial1(metrics::HashName("TestTrial1"),
225 metrics::HashName("Group1"));
226 service
.RegisterSyntheticFieldTrial(trial1
);
228 SyntheticTrialGroup
trial2(metrics::HashName("TestTrial2"),
229 metrics::HashName("Group2"));
230 service
.RegisterSyntheticFieldTrial(trial2
);
231 // Ensure that time has advanced by at least a tick before proceeding.
232 WaitUntilTimeChanges(base::TimeTicks::Now());
234 service
.log_manager_
.BeginLoggingWithLog(scoped_ptr
<MetricsLog
>(
235 new MetricsLog("clientID",
237 MetricsLog::INITIAL_STABILITY_LOG
,
240 // Save the time when the log was started (it's okay for this to be greater
241 // than the time recorded by the above call since it's used to ensure the
243 const base::TimeTicks begin_log_time
= base::TimeTicks::Now();
245 std::vector
<variations::ActiveGroupId
> synthetic_trials
;
246 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
247 EXPECT_EQ(2U, synthetic_trials
.size());
248 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial1", "Group1"));
249 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
251 // Ensure that time has advanced by at least a tick before proceeding.
252 WaitUntilTimeChanges(begin_log_time
);
254 // Change the group for the first trial after the log started.
255 SyntheticTrialGroup
trial3(metrics::HashName("TestTrial1"),
256 metrics::HashName("Group2"));
257 service
.RegisterSyntheticFieldTrial(trial3
);
258 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
259 EXPECT_EQ(1U, synthetic_trials
.size());
260 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
262 // Add a new trial after the log started and confirm that it doesn't show up.
263 SyntheticTrialGroup
trial4(metrics::HashName("TestTrial3"),
264 metrics::HashName("Group3"));
265 service
.RegisterSyntheticFieldTrial(trial4
);
266 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
267 EXPECT_EQ(1U, synthetic_trials
.size());
268 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
270 // Ensure that time has advanced by at least a tick before proceeding.
271 WaitUntilTimeChanges(base::TimeTicks::Now());
273 // Start a new log and ensure all three trials appear in it.
274 service
.log_manager_
.FinishCurrentLog();
275 service
.log_manager_
.BeginLoggingWithLog(
276 scoped_ptr
<MetricsLog
>(new MetricsLog(
277 "clientID", 1, MetricsLog::ONGOING_LOG
, &client
, GetLocalState())));
278 service
.GetCurrentSyntheticFieldTrials(&synthetic_trials
);
279 EXPECT_EQ(3U, synthetic_trials
.size());
280 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial1", "Group2"));
281 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial2", "Group2"));
282 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials
, "TestTrial3", "Group3"));
283 service
.log_manager_
.FinishCurrentLog();
286 TEST_F(MetricsServiceTest
, MetricsServiceObserver
) {
287 metrics::TestMetricsServiceClient client
;
288 MetricsService
service(GetMetricsStateManager(), &client
, GetLocalState());
289 TestMetricsServiceObserver observer1
;
290 TestMetricsServiceObserver observer2
;
292 service
.AddObserver(&observer1
);
293 EXPECT_EQ(0, observer1
.observed());
294 EXPECT_EQ(0, observer2
.observed());
296 service
.OpenNewLog();
297 EXPECT_EQ(1, observer1
.observed());
298 EXPECT_EQ(0, observer2
.observed());
299 service
.log_manager_
.FinishCurrentLog();
301 service
.AddObserver(&observer2
);
303 service
.OpenNewLog();
304 EXPECT_EQ(2, observer1
.observed());
305 EXPECT_EQ(1, observer2
.observed());
306 service
.log_manager_
.FinishCurrentLog();
308 service
.RemoveObserver(&observer1
);
310 service
.OpenNewLog();
311 EXPECT_EQ(2, observer1
.observed());
312 EXPECT_EQ(2, observer2
.observed());
313 service
.log_manager_
.FinishCurrentLog();
315 service
.RemoveObserver(&observer2
);
318 } // namespace metrics