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.
9 #include "chrome/common/metrics/metrics_log_base.h"
10 #include "chrome/common/metrics/metrics_log_manager.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 typedef MetricsLogManager::SerializedLog SerializedLog
;
17 class MetricsLogManagerTest
: public testing::Test
{
20 // Dummy serializer that just stores logs in memory.
21 class DummyLogSerializer
: public MetricsLogManager::LogSerializer
{
23 virtual void SerializeLogs(const std::vector
<SerializedLog
>& logs
,
24 MetricsLogManager::LogType log_type
) {
25 persisted_logs_
[log_type
] = logs
;
28 virtual void DeserializeLogs(MetricsLogManager::LogType log_type
,
29 std::vector
<SerializedLog
>* logs
) {
30 ASSERT_NE(static_cast<void*>(NULL
), logs
);
31 *logs
= persisted_logs_
[log_type
];
34 // Returns the number of logs of the given type.
35 size_t TypeCount(MetricsLogManager::LogType log_type
) {
36 return persisted_logs_
[log_type
].size();
39 // In-memory "persitent storage".
40 std::vector
<SerializedLog
> persisted_logs_
[2];
45 TEST(MetricsLogManagerTest
, StandardFlow
) {
46 MetricsLogManager log_manager
;
48 // Make sure a new manager has a clean slate.
49 EXPECT_EQ(NULL
, log_manager
.current_log());
50 EXPECT_FALSE(log_manager
.has_staged_log());
51 EXPECT_FALSE(log_manager
.has_unsent_logs());
53 // Check that the normal flow works.
54 MetricsLogBase
* initial_log
= new MetricsLogBase("id", 0, "version");
55 log_manager
.BeginLoggingWithLog(initial_log
, MetricsLogManager::INITIAL_LOG
);
56 EXPECT_EQ(initial_log
, log_manager
.current_log());
57 EXPECT_FALSE(log_manager
.has_staged_log());
59 log_manager
.FinishCurrentLog();
60 EXPECT_EQ(NULL
, log_manager
.current_log());
61 EXPECT_TRUE(log_manager
.has_unsent_logs());
62 EXPECT_FALSE(log_manager
.has_staged_log());
64 MetricsLogBase
* second_log
= new MetricsLogBase("id", 0, "version");
65 log_manager
.BeginLoggingWithLog(second_log
, MetricsLogManager::ONGOING_LOG
);
66 EXPECT_EQ(second_log
, log_manager
.current_log());
68 log_manager
.StageNextLogForUpload();
69 EXPECT_TRUE(log_manager
.has_staged_log());
70 EXPECT_FALSE(log_manager
.staged_log_text().empty());
72 log_manager
.DiscardStagedLogXml();
73 log_manager
.DiscardStagedLogProto();
74 EXPECT_EQ(second_log
, log_manager
.current_log());
75 EXPECT_FALSE(log_manager
.has_staged_log());
76 EXPECT_FALSE(log_manager
.has_unsent_logs());
77 EXPECT_TRUE(log_manager
.staged_log_text().empty());
79 EXPECT_FALSE(log_manager
.has_unsent_logs());
82 TEST(MetricsLogManagerTest
, AbandonedLog
) {
83 MetricsLogManager log_manager
;
85 MetricsLogBase
* dummy_log
= new MetricsLogBase("id", 0, "version");
86 log_manager
.BeginLoggingWithLog(dummy_log
, MetricsLogManager::INITIAL_LOG
);
87 EXPECT_EQ(dummy_log
, log_manager
.current_log());
89 log_manager
.DiscardCurrentLog();
90 EXPECT_EQ(NULL
, log_manager
.current_log());
91 EXPECT_FALSE(log_manager
.has_staged_log());
94 TEST(MetricsLogManagerTest
, InterjectedLog
) {
95 MetricsLogManager log_manager
;
97 MetricsLogBase
* ongoing_log
= new MetricsLogBase("id", 0, "version");
98 MetricsLogBase
* temp_log
= new MetricsLogBase("id", 0, "version");
100 log_manager
.BeginLoggingWithLog(ongoing_log
, MetricsLogManager::ONGOING_LOG
);
101 EXPECT_EQ(ongoing_log
, log_manager
.current_log());
103 log_manager
.PauseCurrentLog();
104 EXPECT_EQ(NULL
, log_manager
.current_log());
106 log_manager
.BeginLoggingWithLog(temp_log
, MetricsLogManager::INITIAL_LOG
);
107 EXPECT_EQ(temp_log
, log_manager
.current_log());
108 log_manager
.FinishCurrentLog();
109 EXPECT_EQ(NULL
, log_manager
.current_log());
111 log_manager
.ResumePausedLog();
112 EXPECT_EQ(ongoing_log
, log_manager
.current_log());
114 EXPECT_FALSE(log_manager
.has_staged_log());
115 log_manager
.StageNextLogForUpload();
116 log_manager
.DiscardStagedLogXml();
117 log_manager
.DiscardStagedLogProto();
118 EXPECT_FALSE(log_manager
.has_unsent_logs());
121 TEST(MetricsLogManagerTest
, InterjectedLogPreservesType
) {
122 MetricsLogManager log_manager
;
124 MetricsLogBase
* ongoing_log
= new MetricsLogBase("id", 0, "version");
125 MetricsLogBase
* temp_log
= new MetricsLogBase("id", 0, "version");
127 log_manager
.BeginLoggingWithLog(ongoing_log
, MetricsLogManager::ONGOING_LOG
);
128 log_manager
.PauseCurrentLog();
129 log_manager
.BeginLoggingWithLog(temp_log
, MetricsLogManager::INITIAL_LOG
);
130 log_manager
.FinishCurrentLog();
131 log_manager
.ResumePausedLog();
132 log_manager
.StageNextLogForUpload();
133 log_manager
.DiscardStagedLogXml();
134 log_manager
.DiscardStagedLogProto();
136 // Verify that the remaining log (which is the original ongoing log) still
137 // has the right type.
138 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
139 log_manager
.set_log_serializer(serializer
);
140 log_manager
.FinishCurrentLog();
141 log_manager
.PersistUnsentLogs();
142 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
143 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
146 TEST(MetricsLogManagerTest
, StoreAndLoad
) {
147 std::vector
<SerializedLog
> initial_logs
;
148 std::vector
<SerializedLog
> ongoing_logs
;
150 // Set up some in-progress logging in a scoped log manager simulating the
151 // leadup to quitting, then persist as would be done on quit.
153 MetricsLogManager log_manager
;
154 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
155 log_manager
.set_log_serializer(serializer
);
156 // Simulate a log having already been unsent from a previous session.
157 SerializedLog log
= {"xml", "proto"};
158 serializer
->persisted_logs_
[MetricsLogManager::ONGOING_LOG
].push_back(log
);
159 EXPECT_FALSE(log_manager
.has_unsent_logs());
160 log_manager
.LoadPersistedUnsentLogs();
161 EXPECT_TRUE(log_manager
.has_unsent_logs());
163 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
164 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
165 log_manager
.BeginLoggingWithLog(log1
, MetricsLogManager::INITIAL_LOG
);
166 log_manager
.FinishCurrentLog();
167 log_manager
.BeginLoggingWithLog(log2
, MetricsLogManager::ONGOING_LOG
);
168 log_manager
.StageNextLogForUpload();
169 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
170 log_manager
.FinishCurrentLog();
172 // Nothing should be written out until PersistUnsentLogs is called.
173 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
174 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
175 log_manager
.PersistUnsentLogs();
176 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
177 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
179 // Save the logs to transfer over to a new serializer (since log_manager
180 // owns |serializer|, so it's about to go away.
181 initial_logs
= serializer
->persisted_logs_
[MetricsLogManager::INITIAL_LOG
];
182 ongoing_logs
= serializer
->persisted_logs_
[MetricsLogManager::ONGOING_LOG
];
185 // Now simulate the relaunch, ensure that the log manager restores
186 // everything correctly, and verify that once the are handled they are not
189 MetricsLogManager log_manager
;
191 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
192 serializer
->persisted_logs_
[MetricsLogManager::INITIAL_LOG
] = initial_logs
;
193 serializer
->persisted_logs_
[MetricsLogManager::ONGOING_LOG
] = ongoing_logs
;
195 log_manager
.set_log_serializer(serializer
);
196 log_manager
.LoadPersistedUnsentLogs();
197 EXPECT_TRUE(log_manager
.has_unsent_logs());
199 log_manager
.StageNextLogForUpload();
200 log_manager
.DiscardStagedLogXml();
201 log_manager
.DiscardStagedLogProto();
202 // The initial log should be sent first; update the persisted storage to
204 log_manager
.PersistUnsentLogs();
205 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
206 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
208 // Handle the first ongoing log.
209 log_manager
.StageNextLogForUpload();
210 log_manager
.DiscardStagedLogXml();
211 log_manager
.DiscardStagedLogProto();
212 EXPECT_TRUE(log_manager
.has_unsent_logs());
214 // Handle the last log.
215 log_manager
.StageNextLogForUpload();
216 log_manager
.DiscardStagedLogXml();
217 log_manager
.DiscardStagedLogProto();
218 EXPECT_FALSE(log_manager
.has_unsent_logs());
220 // Nothing should have changed "on disk" since PersistUnsentLogs hasn't been
222 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
223 // Persist, and make sure nothing is left.
224 log_manager
.PersistUnsentLogs();
225 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
226 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
230 TEST(MetricsLogManagerTest
, StoreStagedLogTypes
) {
231 // Ensure that types are preserved when storing staged logs.
233 MetricsLogManager log_manager
;
234 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
235 log_manager
.set_log_serializer(serializer
);
237 MetricsLogBase
* log
= new MetricsLogBase("id", 0, "version");
238 log_manager
.BeginLoggingWithLog(log
, MetricsLogManager::ONGOING_LOG
);
239 log_manager
.FinishCurrentLog();
240 log_manager
.StageNextLogForUpload();
241 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
242 log_manager
.PersistUnsentLogs();
244 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
245 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
249 MetricsLogManager log_manager
;
250 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
251 log_manager
.set_log_serializer(serializer
);
253 MetricsLogBase
* log
= new MetricsLogBase("id", 0, "version");
254 log_manager
.BeginLoggingWithLog(log
, MetricsLogManager::INITIAL_LOG
);
255 log_manager
.FinishCurrentLog();
256 log_manager
.StageNextLogForUpload();
257 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
258 log_manager
.PersistUnsentLogs();
260 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
261 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
265 TEST(MetricsLogManagerTest
, LargeLogDiscarding
) {
266 MetricsLogManager log_manager
;
267 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
268 log_manager
.set_log_serializer(serializer
);
269 // Set the size threshold very low, to verify that it's honored.
270 log_manager
.set_max_ongoing_log_store_size(1);
272 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
273 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
274 log_manager
.BeginLoggingWithLog(log1
, MetricsLogManager::INITIAL_LOG
);
275 log_manager
.FinishCurrentLog();
276 log_manager
.BeginLoggingWithLog(log2
, MetricsLogManager::ONGOING_LOG
);
277 log_manager
.FinishCurrentLog();
279 // Only the ongoing log should be written out, due to the threshold.
280 log_manager
.PersistUnsentLogs();
281 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
282 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
285 TEST(MetricsLogManagerTest
, ProvisionalStoreStandardFlow
) {
286 // Ensure that provisional store works, and discards the correct log.
288 MetricsLogManager log_manager
;
289 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
290 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
291 log_manager
.BeginLoggingWithLog(log1
, MetricsLogManager::INITIAL_LOG
);
292 log_manager
.FinishCurrentLog();
293 log_manager
.BeginLoggingWithLog(log2
, MetricsLogManager::ONGOING_LOG
);
294 log_manager
.StageNextLogForUpload();
295 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
296 log_manager
.FinishCurrentLog();
297 log_manager
.DiscardLastProvisionalStore();
299 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
300 log_manager
.set_log_serializer(serializer
);
301 log_manager
.PersistUnsentLogs();
302 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogManager::INITIAL_LOG
));
303 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
307 TEST(MetricsLogManagerTest
, ProvisionalStoreNoop
) {
308 // Ensure that trying to drop a sent log is a no-op, even if another log has
309 // since been staged.
311 MetricsLogManager log_manager
;
312 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
313 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
314 log_manager
.BeginLoggingWithLog(log1
, MetricsLogManager::ONGOING_LOG
);
315 log_manager
.FinishCurrentLog();
316 log_manager
.StageNextLogForUpload();
317 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
318 log_manager
.StageNextLogForUpload();
319 log_manager
.DiscardStagedLogXml();
320 log_manager
.DiscardStagedLogProto();
321 log_manager
.BeginLoggingWithLog(log2
, MetricsLogManager::ONGOING_LOG
);
322 log_manager
.FinishCurrentLog();
323 log_manager
.StageNextLogForUpload();
324 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
325 log_manager
.DiscardLastProvisionalStore();
327 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
328 log_manager
.set_log_serializer(serializer
);
329 log_manager
.PersistUnsentLogs();
330 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
333 // Ensure that trying to drop more than once is a no-op
335 MetricsLogManager log_manager
;
336 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
337 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
338 log_manager
.BeginLoggingWithLog(log1
, MetricsLogManager::ONGOING_LOG
);
339 log_manager
.FinishCurrentLog();
340 log_manager
.StageNextLogForUpload();
341 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
342 log_manager
.BeginLoggingWithLog(log2
, MetricsLogManager::ONGOING_LOG
);
343 log_manager
.FinishCurrentLog();
344 log_manager
.StageNextLogForUpload();
345 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
346 log_manager
.DiscardLastProvisionalStore();
347 log_manager
.DiscardLastProvisionalStore();
349 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
350 log_manager
.set_log_serializer(serializer
);
351 log_manager
.PersistUnsentLogs();
352 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogManager::ONGOING_LOG
));
356 // Test that discarding just the XML log, then the protobuf log, works.
357 TEST(MetricsLogManagerTest
, DiscardXmlLogFirst
) {
358 MetricsLogManager log_manager
;
359 EXPECT_FALSE(log_manager
.has_staged_log());
360 EXPECT_FALSE(log_manager
.has_staged_log_xml());
361 EXPECT_FALSE(log_manager
.has_staged_log_proto());
363 MetricsLogBase
* initial_log
= new MetricsLogBase("id", 0, "version");
364 log_manager
.BeginLoggingWithLog(initial_log
, MetricsLogManager::INITIAL_LOG
);
365 log_manager
.FinishCurrentLog();
366 EXPECT_FALSE(log_manager
.has_staged_log());
367 EXPECT_FALSE(log_manager
.has_staged_log_xml());
368 EXPECT_FALSE(log_manager
.has_staged_log_proto());
370 log_manager
.StageNextLogForUpload();
371 EXPECT_TRUE(log_manager
.has_staged_log());
372 EXPECT_TRUE(log_manager
.has_staged_log_xml());
373 EXPECT_TRUE(log_manager
.has_staged_log_proto());
374 EXPECT_FALSE(log_manager
.staged_log_text().empty());
376 log_manager
.DiscardStagedLogXml();
377 EXPECT_TRUE(log_manager
.has_staged_log());
378 EXPECT_FALSE(log_manager
.has_staged_log_xml());
379 EXPECT_TRUE(log_manager
.has_staged_log_proto());
380 EXPECT_FALSE(log_manager
.staged_log_text().empty());
382 log_manager
.DiscardStagedLogProto();
383 EXPECT_FALSE(log_manager
.has_staged_log());
384 EXPECT_FALSE(log_manager
.has_staged_log_xml());
385 EXPECT_FALSE(log_manager
.has_staged_log_proto());
386 EXPECT_TRUE(log_manager
.staged_log_text().empty());
389 // Test that discarding just the protobuf log, then the XML log, works.
390 TEST(MetricsLogManagerTest
, DiscardProtoLogFirst
) {
391 MetricsLogManager log_manager
;
392 EXPECT_FALSE(log_manager
.has_staged_log());
393 EXPECT_FALSE(log_manager
.has_staged_log_xml());
394 EXPECT_FALSE(log_manager
.has_staged_log_proto());
396 MetricsLogBase
* initial_log
= new MetricsLogBase("id", 0, "version");
397 log_manager
.BeginLoggingWithLog(initial_log
, MetricsLogManager::INITIAL_LOG
);
398 log_manager
.FinishCurrentLog();
399 EXPECT_FALSE(log_manager
.has_staged_log());
400 EXPECT_FALSE(log_manager
.has_staged_log_xml());
401 EXPECT_FALSE(log_manager
.has_staged_log_proto());
403 log_manager
.StageNextLogForUpload();
404 EXPECT_TRUE(log_manager
.has_staged_log());
405 EXPECT_TRUE(log_manager
.has_staged_log_xml());
406 EXPECT_TRUE(log_manager
.has_staged_log_proto());
407 EXPECT_FALSE(log_manager
.staged_log_text().empty());
409 log_manager
.DiscardStagedLogProto();
410 EXPECT_TRUE(log_manager
.has_staged_log());
411 EXPECT_TRUE(log_manager
.has_staged_log_xml());
412 EXPECT_FALSE(log_manager
.has_staged_log_proto());
413 EXPECT_FALSE(log_manager
.staged_log_text().empty());
415 log_manager
.DiscardStagedLogXml();
416 EXPECT_FALSE(log_manager
.has_staged_log());
417 EXPECT_FALSE(log_manager
.has_staged_log_xml());
418 EXPECT_FALSE(log_manager
.has_staged_log_proto());
419 EXPECT_TRUE(log_manager
.staged_log_text().empty());