OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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_service.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/prefs/testing_pref_service.h" | |
11 #include "base/threading/platform_thread.h" | |
12 #include "chrome/browser/google/google_util.h" | |
13 #include "chrome/common/pref_names.h" | |
14 #include "chrome/test/base/scoped_testing_local_state.h" | |
15 #include "chrome/test/base/testing_browser_process.h" | |
16 #include "components/metrics/compression_utils.h" | |
17 #include "components/metrics/metrics_log.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 "content/public/test/test_browser_thread_bundle.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 #if defined(OS_CHROMEOS) | |
26 #include "chromeos/login/login_state.h" | |
27 #endif // defined(OS_CHROMEOS) | |
28 | |
29 namespace { | |
30 | |
31 using metrics::MetricsLogManager; | |
32 | |
33 class TestMetricsService : public MetricsService { | |
34 public: | |
35 TestMetricsService(metrics::MetricsStateManager* state_manager, | |
36 metrics::MetricsServiceClient* client, | |
37 PrefService* local_state) | |
38 : MetricsService(state_manager, client, local_state) {} | |
39 virtual ~TestMetricsService() {} | |
40 | |
41 using MetricsService::log_manager; | |
42 | |
43 private: | |
44 DISALLOW_COPY_AND_ASSIGN(TestMetricsService); | |
45 }; | |
46 | |
47 class TestMetricsLog : public MetricsLog { | |
48 public: | |
49 TestMetricsLog(const std::string& client_id, | |
50 int session_id, | |
51 metrics::MetricsServiceClient* client, | |
52 PrefService* local_state) | |
53 : MetricsLog(client_id, | |
54 session_id, | |
55 MetricsLog::ONGOING_LOG, | |
56 client, | |
57 local_state) {} | |
58 | |
59 virtual ~TestMetricsLog() {} | |
60 | |
61 private: | |
62 DISALLOW_COPY_AND_ASSIGN(TestMetricsLog); | |
63 }; | |
64 | |
65 class MetricsServiceTest : public testing::Test { | |
66 public: | |
67 MetricsServiceTest() : is_metrics_reporting_enabled_(false) { | |
68 MetricsService::RegisterPrefs(testing_local_state_.registry()); | |
69 metrics_state_manager_ = metrics::MetricsStateManager::Create( | |
70 GetLocalState(), | |
71 base::Bind(&MetricsServiceTest::is_metrics_reporting_enabled, | |
72 base::Unretained(this))); | |
73 #if defined(OS_CHROMEOS) | |
74 // TODO(blundell): Remove this code once MetricsService no longer creates | |
75 // ChromeOSMetricsProvider. Also remove the #include of login_state.h. | |
76 // (http://crbug.com/375776) | |
77 if (!chromeos::LoginState::IsInitialized()) | |
78 chromeos::LoginState::Initialize(); | |
79 #endif // defined(OS_CHROMEOS) | |
80 } | |
81 | |
82 virtual ~MetricsServiceTest() { | |
83 MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE, | |
84 GetLocalState()); | |
85 #if defined(OS_CHROMEOS) | |
86 // TODO(blundell): Remove this code once MetricsService no longer creates | |
87 // ChromeOSMetricsProvider. | |
88 chromeos::LoginState::Shutdown(); | |
89 #endif // defined(OS_CHROMEOS) | |
90 } | |
91 | |
92 metrics::MetricsStateManager* GetMetricsStateManager() { | |
93 return metrics_state_manager_.get(); | |
94 } | |
95 | |
96 PrefService* GetLocalState() { return &testing_local_state_; } | |
97 | |
98 // Sets metrics reporting as enabled for testing. | |
99 void EnableMetricsReporting() { | |
100 is_metrics_reporting_enabled_ = true; | |
101 } | |
102 | |
103 // Waits until base::TimeTicks::Now() no longer equals |value|. This should | |
104 // take between 1-15ms per the documented resolution of base::TimeTicks. | |
105 void WaitUntilTimeChanges(const base::TimeTicks& value) { | |
106 while (base::TimeTicks::Now() == value) { | |
107 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); | |
108 } | |
109 } | |
110 | |
111 // Returns true if there is a synthetic trial in the given vector that matches | |
112 // the given trial name and trial group; returns false otherwise. | |
113 bool HasSyntheticTrial( | |
114 const std::vector<variations::ActiveGroupId>& synthetic_trials, | |
115 const std::string& trial_name, | |
116 const std::string& trial_group) { | |
117 uint32 trial_name_hash = metrics::HashName(trial_name); | |
118 uint32 trial_group_hash = metrics::HashName(trial_group); | |
119 for (std::vector<variations::ActiveGroupId>::const_iterator it = | |
120 synthetic_trials.begin(); | |
121 it != synthetic_trials.end(); ++it) { | |
122 if ((*it).name == trial_name_hash && (*it).group == trial_group_hash) | |
123 return true; | |
124 } | |
125 return false; | |
126 } | |
127 | |
128 private: | |
129 bool is_metrics_reporting_enabled() const { | |
130 return is_metrics_reporting_enabled_; | |
131 } | |
132 | |
133 content::TestBrowserThreadBundle thread_bundle_; | |
134 bool is_metrics_reporting_enabled_; | |
135 TestingPrefServiceSimple testing_local_state_; | |
136 scoped_ptr<metrics::MetricsStateManager> metrics_state_manager_; | |
137 | |
138 DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest); | |
139 }; | |
140 | |
141 class TestMetricsServiceObserver : public MetricsServiceObserver { | |
142 public: | |
143 TestMetricsServiceObserver(): observed_(0) {} | |
144 virtual ~TestMetricsServiceObserver() {} | |
145 | |
146 virtual void OnDidCreateMetricsLog() OVERRIDE { | |
147 ++observed_; | |
148 } | |
149 int observed() const { return observed_; } | |
150 | |
151 private: | |
152 int observed_; | |
153 | |
154 DISALLOW_COPY_AND_ASSIGN(TestMetricsServiceObserver); | |
155 }; | |
156 | |
157 } // namespace | |
158 | |
159 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) { | |
160 EnableMetricsReporting(); | |
161 GetLocalState()->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true); | |
162 | |
163 metrics::TestMetricsServiceClient client; | |
164 TestMetricsService service( | |
165 GetMetricsStateManager(), &client, GetLocalState()); | |
166 service.InitializeMetricsRecordingState(); | |
167 // No initial stability log should be generated. | |
168 EXPECT_FALSE(service.log_manager()->has_unsent_logs()); | |
169 EXPECT_FALSE(service.log_manager()->has_staged_log()); | |
170 } | |
171 | |
172 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCrash) { | |
173 // TODO(asvitkine): Eliminate using |testing_local_state| in favor of using | |
174 // |GetLocalState()| once MetricsService no longer internally creates metrics | |
175 // providers that rely on g_browser_process->local_state() being correctly | |
176 // set up. crbug.com/375776. | |
177 ScopedTestingLocalState testing_local_state( | |
178 TestingBrowserProcess::GetGlobal()); | |
179 TestingPrefServiceSimple* local_state = testing_local_state.Get(); | |
180 EnableMetricsReporting(); | |
181 local_state->ClearPref(metrics::prefs::kStabilityExitedCleanly); | |
182 | |
183 // Set up prefs to simulate restarting after a crash. | |
184 | |
185 // Save an existing system profile to prefs, to correspond to what would be | |
186 // saved from a previous session. | |
187 metrics::TestMetricsServiceClient client; | |
188 TestMetricsLog log("client", 1, &client, local_state); | |
189 log.RecordEnvironment(std::vector<metrics::MetricsProvider*>(), | |
190 std::vector<variations::ActiveGroupId>()); | |
191 | |
192 // Record stability build time and version from previous session, so that | |
193 // stability metrics (including exited cleanly flag) won't be cleared. | |
194 local_state->SetInt64(metrics::prefs::kStabilityStatsBuildTime, | |
195 MetricsLog::GetBuildTime()); | |
196 local_state->SetString(metrics::prefs::kStabilityStatsVersion, | |
197 client.GetVersionString()); | |
198 | |
199 local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false); | |
200 | |
201 TestMetricsService service(GetMetricsStateManager(), &client, local_state); | |
202 service.InitializeMetricsRecordingState(); | |
203 | |
204 // The initial stability log should be generated and persisted in unsent logs. | |
205 MetricsLogManager* log_manager = service.log_manager(); | |
206 EXPECT_TRUE(log_manager->has_unsent_logs()); | |
207 EXPECT_FALSE(log_manager->has_staged_log()); | |
208 | |
209 // Stage the log and retrieve it. | |
210 log_manager->StageNextLogForUpload(); | |
211 EXPECT_TRUE(log_manager->has_staged_log()); | |
212 | |
213 std::string uncompressed_log; | |
214 EXPECT_TRUE(metrics::GzipUncompress(log_manager->staged_log(), | |
215 &uncompressed_log)); | |
216 | |
217 metrics::ChromeUserMetricsExtension uma_log; | |
218 EXPECT_TRUE(uma_log.ParseFromString(uncompressed_log)); | |
219 | |
220 EXPECT_TRUE(uma_log.has_client_id()); | |
221 EXPECT_TRUE(uma_log.has_session_id()); | |
222 EXPECT_TRUE(uma_log.has_system_profile()); | |
223 EXPECT_EQ(0, uma_log.user_action_event_size()); | |
224 EXPECT_EQ(0, uma_log.omnibox_event_size()); | |
225 EXPECT_EQ(0, uma_log.histogram_event_size()); | |
226 EXPECT_EQ(0, uma_log.profiler_event_size()); | |
227 EXPECT_EQ(0, uma_log.perf_data_size()); | |
228 | |
229 EXPECT_EQ(1, uma_log.system_profile().stability().crash_count()); | |
230 } | |
231 | |
232 TEST_F(MetricsServiceTest, RegisterSyntheticTrial) { | |
233 metrics::TestMetricsServiceClient client; | |
234 MetricsService service(GetMetricsStateManager(), &client, GetLocalState()); | |
235 | |
236 // Add two synthetic trials and confirm that they show up in the list. | |
237 SyntheticTrialGroup trial1(metrics::HashName("TestTrial1"), | |
238 metrics::HashName("Group1")); | |
239 service.RegisterSyntheticFieldTrial(trial1); | |
240 | |
241 SyntheticTrialGroup trial2(metrics::HashName("TestTrial2"), | |
242 metrics::HashName("Group2")); | |
243 service.RegisterSyntheticFieldTrial(trial2); | |
244 // Ensure that time has advanced by at least a tick before proceeding. | |
245 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
246 | |
247 service.log_manager_.BeginLoggingWithLog(scoped_ptr<MetricsLog>( | |
248 new MetricsLog("clientID", | |
249 1, | |
250 MetricsLog::INITIAL_STABILITY_LOG, | |
251 &client, | |
252 GetLocalState()))); | |
253 // Save the time when the log was started (it's okay for this to be greater | |
254 // than the time recorded by the above call since it's used to ensure the | |
255 // value changes). | |
256 const base::TimeTicks begin_log_time = base::TimeTicks::Now(); | |
257 | |
258 std::vector<variations::ActiveGroupId> synthetic_trials; | |
259 service.GetCurrentSyntheticFieldTrials(&synthetic_trials); | |
260 EXPECT_EQ(2U, synthetic_trials.size()); | |
261 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1")); | |
262 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
263 | |
264 // Ensure that time has advanced by at least a tick before proceeding. | |
265 WaitUntilTimeChanges(begin_log_time); | |
266 | |
267 // Change the group for the first trial after the log started. | |
268 SyntheticTrialGroup trial3(metrics::HashName("TestTrial1"), | |
269 metrics::HashName("Group2")); | |
270 service.RegisterSyntheticFieldTrial(trial3); | |
271 service.GetCurrentSyntheticFieldTrials(&synthetic_trials); | |
272 EXPECT_EQ(1U, synthetic_trials.size()); | |
273 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
274 | |
275 // Add a new trial after the log started and confirm that it doesn't show up. | |
276 SyntheticTrialGroup trial4(metrics::HashName("TestTrial3"), | |
277 metrics::HashName("Group3")); | |
278 service.RegisterSyntheticFieldTrial(trial4); | |
279 service.GetCurrentSyntheticFieldTrials(&synthetic_trials); | |
280 EXPECT_EQ(1U, synthetic_trials.size()); | |
281 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
282 | |
283 // Ensure that time has advanced by at least a tick before proceeding. | |
284 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
285 | |
286 // Start a new log and ensure all three trials appear in it. | |
287 service.log_manager_.FinishCurrentLog(); | |
288 service.log_manager_.BeginLoggingWithLog( | |
289 scoped_ptr<MetricsLog>(new MetricsLog( | |
290 "clientID", 1, MetricsLog::ONGOING_LOG, &client, GetLocalState()))); | |
291 service.GetCurrentSyntheticFieldTrials(&synthetic_trials); | |
292 EXPECT_EQ(3U, synthetic_trials.size()); | |
293 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2")); | |
294 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
295 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3")); | |
296 service.log_manager_.FinishCurrentLog(); | |
297 } | |
298 | |
299 TEST_F(MetricsServiceTest, MetricsServiceObserver) { | |
300 metrics::TestMetricsServiceClient client; | |
301 MetricsService service(GetMetricsStateManager(), &client, GetLocalState()); | |
302 TestMetricsServiceObserver observer1; | |
303 TestMetricsServiceObserver observer2; | |
304 | |
305 service.AddObserver(&observer1); | |
306 EXPECT_EQ(0, observer1.observed()); | |
307 EXPECT_EQ(0, observer2.observed()); | |
308 | |
309 service.OpenNewLog(); | |
310 EXPECT_EQ(1, observer1.observed()); | |
311 EXPECT_EQ(0, observer2.observed()); | |
312 service.log_manager_.FinishCurrentLog(); | |
313 | |
314 service.AddObserver(&observer2); | |
315 | |
316 service.OpenNewLog(); | |
317 EXPECT_EQ(2, observer1.observed()); | |
318 EXPECT_EQ(1, observer2.observed()); | |
319 service.log_manager_.FinishCurrentLog(); | |
320 | |
321 service.RemoveObserver(&observer1); | |
322 | |
323 service.OpenNewLog(); | |
324 EXPECT_EQ(2, observer1.observed()); | |
325 EXPECT_EQ(2, observer2.observed()); | |
326 service.log_manager_.FinishCurrentLog(); | |
327 | |
328 service.RemoveObserver(&observer2); | |
329 } | |
OLD | NEW |