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_log_manager.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "components/metrics/metrics_log.h"
14 #include "components/metrics/metrics_pref_names.h"
15 #include "components/metrics/test_metrics_service_client.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace metrics {
19
20 namespace {
21
22 // Dummy serializer that just stores logs in memory.
23 class TestLogPrefService : public TestingPrefServiceSimple {
24 public:
TestLogPrefService()25 TestLogPrefService() {
26 registry()->RegisterListPref(prefs::kMetricsInitialLogs);
27 registry()->RegisterListPref(prefs::kMetricsInitialLogsOld);
28 registry()->RegisterListPref(prefs::kMetricsOngoingLogs);
29 registry()->RegisterListPref(prefs::kMetricsOngoingLogsOld);
30 }
31
32 // Returns the number of logs of the given type.
TypeCount(MetricsLog::LogType log_type)33 size_t TypeCount(MetricsLog::LogType log_type) {
34 int list_length = 0;
35 if (log_type == MetricsLog::INITIAL_STABILITY_LOG)
36 list_length = GetList(prefs::kMetricsInitialLogs)->GetSize();
37 else
38 list_length = GetList(prefs::kMetricsOngoingLogs)->GetSize();
39 return list_length / 2;
40 }
41 };
42
43 } // namespace
44
TEST(MetricsLogManagerTest,StandardFlow)45 TEST(MetricsLogManagerTest, StandardFlow) {
46 TestMetricsServiceClient client;
47 TestLogPrefService pref_service;
48 MetricsLogManager log_manager(&pref_service, 0);
49
50 // Make sure a new manager has a clean slate.
51 EXPECT_EQ(NULL, log_manager.current_log());
52 EXPECT_FALSE(log_manager.has_staged_log());
53 EXPECT_FALSE(log_manager.has_unsent_logs());
54
55 // Check that the normal flow works.
56 MetricsLog* initial_log = new MetricsLog(
57 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service);
58 log_manager.BeginLoggingWithLog(make_scoped_ptr(initial_log));
59 EXPECT_EQ(initial_log, log_manager.current_log());
60 EXPECT_FALSE(log_manager.has_staged_log());
61
62 log_manager.FinishCurrentLog();
63 EXPECT_EQ(NULL, log_manager.current_log());
64 EXPECT_TRUE(log_manager.has_unsent_logs());
65 EXPECT_FALSE(log_manager.has_staged_log());
66
67 MetricsLog* second_log =
68 new MetricsLog("id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service);
69 log_manager.BeginLoggingWithLog(make_scoped_ptr(second_log));
70 EXPECT_EQ(second_log, log_manager.current_log());
71
72 log_manager.StageNextLogForUpload();
73 EXPECT_TRUE(log_manager.has_staged_log());
74 EXPECT_FALSE(log_manager.staged_log().empty());
75
76 log_manager.DiscardStagedLog();
77 EXPECT_EQ(second_log, log_manager.current_log());
78 EXPECT_FALSE(log_manager.has_staged_log());
79 EXPECT_FALSE(log_manager.has_unsent_logs());
80
81 EXPECT_FALSE(log_manager.has_unsent_logs());
82 }
83
TEST(MetricsLogManagerTest,AbandonedLog)84 TEST(MetricsLogManagerTest, AbandonedLog) {
85 TestMetricsServiceClient client;
86 TestLogPrefService pref_service;
87 MetricsLogManager log_manager(&pref_service, 0);
88
89 MetricsLog* dummy_log = new MetricsLog(
90 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service);
91 log_manager.BeginLoggingWithLog(make_scoped_ptr(dummy_log));
92 EXPECT_EQ(dummy_log, log_manager.current_log());
93
94 log_manager.DiscardCurrentLog();
95 EXPECT_EQ(NULL, log_manager.current_log());
96 EXPECT_FALSE(log_manager.has_staged_log());
97 }
98
TEST(MetricsLogManagerTest,InterjectedLog)99 TEST(MetricsLogManagerTest, InterjectedLog) {
100 TestMetricsServiceClient client;
101 TestLogPrefService pref_service;
102 MetricsLogManager log_manager(&pref_service, 0);
103
104 MetricsLog* ongoing_log =
105 new MetricsLog("id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service);
106 MetricsLog* temp_log = new MetricsLog(
107 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service);
108
109 log_manager.BeginLoggingWithLog(make_scoped_ptr(ongoing_log));
110 EXPECT_EQ(ongoing_log, log_manager.current_log());
111
112 log_manager.PauseCurrentLog();
113 EXPECT_EQ(NULL, log_manager.current_log());
114
115 log_manager.BeginLoggingWithLog(make_scoped_ptr(temp_log));
116 EXPECT_EQ(temp_log, log_manager.current_log());
117 log_manager.FinishCurrentLog();
118 EXPECT_EQ(NULL, log_manager.current_log());
119
120 log_manager.ResumePausedLog();
121 EXPECT_EQ(ongoing_log, log_manager.current_log());
122
123 EXPECT_FALSE(log_manager.has_staged_log());
124 log_manager.StageNextLogForUpload();
125 log_manager.DiscardStagedLog();
126 EXPECT_FALSE(log_manager.has_unsent_logs());
127 }
128
TEST(MetricsLogManagerTest,InterjectedLogPreservesType)129 TEST(MetricsLogManagerTest, InterjectedLogPreservesType) {
130 TestMetricsServiceClient client;
131 TestLogPrefService pref_service;
132 MetricsLogManager log_manager(&pref_service, 0);
133 log_manager.LoadPersistedUnsentLogs();
134
135 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
136 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
137 log_manager.PauseCurrentLog();
138 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
139 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
140 log_manager.FinishCurrentLog();
141 log_manager.ResumePausedLog();
142 log_manager.StageNextLogForUpload();
143 log_manager.DiscardStagedLog();
144
145 // Verify that the remaining log (which is the original ongoing log) still
146 // has the right type.
147 log_manager.FinishCurrentLog();
148 log_manager.PersistUnsentLogs();
149 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
150 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
151 }
152
TEST(MetricsLogManagerTest,StoreAndLoad)153 TEST(MetricsLogManagerTest, StoreAndLoad) {
154 TestMetricsServiceClient client;
155 TestLogPrefService pref_service;
156 // Set up some in-progress logging in a scoped log manager simulating the
157 // leadup to quitting, then persist as would be done on quit.
158 {
159 MetricsLogManager log_manager(&pref_service, 0);
160 log_manager.LoadPersistedUnsentLogs();
161
162 // Simulate a log having already been unsent from a previous session.
163 {
164 std::string log("proto");
165 PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs,
166 prefs::kMetricsOngoingLogsOld, 1, 1, 0);
167 ongoing_logs.StoreLog(log);
168 ongoing_logs.SerializeLogs();
169 }
170 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
171 EXPECT_FALSE(log_manager.has_unsent_logs());
172 log_manager.LoadPersistedUnsentLogs();
173 EXPECT_TRUE(log_manager.has_unsent_logs());
174
175 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
176 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
177 log_manager.FinishCurrentLog();
178 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
179 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
180 log_manager.StageNextLogForUpload();
181 log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
182 log_manager.FinishCurrentLog();
183
184 // Nothing should be written out until PersistUnsentLogs is called.
185 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
186 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
187 log_manager.PersistUnsentLogs();
188 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
189 EXPECT_EQ(2U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
190 }
191
192 // Now simulate the relaunch, ensure that the log manager restores
193 // everything correctly, and verify that once the are handled they are not
194 // re-persisted.
195 {
196 MetricsLogManager log_manager(&pref_service, 0);
197 log_manager.LoadPersistedUnsentLogs();
198 EXPECT_TRUE(log_manager.has_unsent_logs());
199
200 log_manager.StageNextLogForUpload();
201 log_manager.DiscardStagedLog();
202 // The initial log should be sent first; update the persisted storage to
203 // verify.
204 log_manager.PersistUnsentLogs();
205 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
206 EXPECT_EQ(2U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
207
208 // Handle the first ongoing log.
209 log_manager.StageNextLogForUpload();
210 log_manager.DiscardStagedLog();
211 EXPECT_TRUE(log_manager.has_unsent_logs());
212
213 // Handle the last log.
214 log_manager.StageNextLogForUpload();
215 log_manager.DiscardStagedLog();
216 EXPECT_FALSE(log_manager.has_unsent_logs());
217
218 // Nothing should have changed "on disk" since PersistUnsentLogs hasn't been
219 // called again.
220 EXPECT_EQ(2U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
221 // Persist, and make sure nothing is left.
222 log_manager.PersistUnsentLogs();
223 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
224 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
225 }
226 }
227
TEST(MetricsLogManagerTest,StoreStagedLogTypes)228 TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
229 TestMetricsServiceClient client;
230
231 // Ensure that types are preserved when storing staged logs.
232 {
233 TestLogPrefService pref_service;
234 MetricsLogManager log_manager(&pref_service, 0);
235 log_manager.LoadPersistedUnsentLogs();
236
237 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
238 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
239 log_manager.FinishCurrentLog();
240 log_manager.StageNextLogForUpload();
241 log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
242 log_manager.PersistUnsentLogs();
243
244 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
245 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
246 }
247
248 {
249 TestLogPrefService pref_service;
250 MetricsLogManager log_manager(&pref_service, 0);
251 log_manager.LoadPersistedUnsentLogs();
252
253 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
254 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
255 log_manager.FinishCurrentLog();
256 log_manager.StageNextLogForUpload();
257 log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
258 log_manager.PersistUnsentLogs();
259
260 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
261 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
262 }
263 }
264
TEST(MetricsLogManagerTest,LargeLogDiscarding)265 TEST(MetricsLogManagerTest, LargeLogDiscarding) {
266 TestMetricsServiceClient client;
267 TestLogPrefService pref_service;
268 // Set the size threshold very low, to verify that it's honored.
269 MetricsLogManager log_manager(&pref_service, 1);
270 log_manager.LoadPersistedUnsentLogs();
271
272 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
273 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
274 log_manager.FinishCurrentLog();
275 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
276 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
277 log_manager.FinishCurrentLog();
278
279 // Only the ongoing log should be written out, due to the threshold.
280 log_manager.PersistUnsentLogs();
281 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
282 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
283 }
284
TEST(MetricsLogManagerTest,ProvisionalStoreStandardFlow)285 TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) {
286 TestMetricsServiceClient client;
287
288 // Ensure that provisional store works, and discards the correct log.
289 {
290 TestLogPrefService pref_service;
291 MetricsLogManager log_manager(&pref_service, 0);
292 log_manager.LoadPersistedUnsentLogs();
293
294 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
295 "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
296 log_manager.FinishCurrentLog();
297 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
298 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
299 log_manager.StageNextLogForUpload();
300 log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
301 log_manager.FinishCurrentLog();
302 log_manager.DiscardLastProvisionalStore();
303
304 log_manager.PersistUnsentLogs();
305 EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
306 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
307 }
308 }
309
TEST(MetricsLogManagerTest,ProvisionalStoreNoop)310 TEST(MetricsLogManagerTest, ProvisionalStoreNoop) {
311 TestMetricsServiceClient client;
312
313 // Ensure that trying to drop a sent log is a no-op, even if another log has
314 // since been staged.
315 {
316 TestLogPrefService pref_service;
317 MetricsLogManager log_manager(&pref_service, 0);
318 log_manager.LoadPersistedUnsentLogs();
319
320 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
321 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
322 log_manager.FinishCurrentLog();
323 log_manager.StageNextLogForUpload();
324 log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
325 log_manager.StageNextLogForUpload();
326 log_manager.DiscardStagedLog();
327 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
328 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
329 log_manager.FinishCurrentLog();
330 log_manager.StageNextLogForUpload();
331 log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
332 log_manager.DiscardLastProvisionalStore();
333
334 log_manager.PersistUnsentLogs();
335 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
336 }
337
338 // Ensure that trying to drop more than once is a no-op
339 {
340 TestLogPrefService pref_service;
341 MetricsLogManager log_manager(&pref_service, 0);
342 log_manager.LoadPersistedUnsentLogs();
343
344 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
345 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
346 log_manager.FinishCurrentLog();
347 log_manager.StageNextLogForUpload();
348 log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
349 log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
350 "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
351 log_manager.FinishCurrentLog();
352 log_manager.StageNextLogForUpload();
353 log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
354 log_manager.DiscardLastProvisionalStore();
355 log_manager.DiscardLastProvisionalStore();
356
357 log_manager.PersistUnsentLogs();
358 EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
359 }
360 }
361
362 } // namespace metrics
363