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.
5 #include "chrome/common/metrics/metrics_log_manager.h"
11 #include "base/sha1.h"
12 #include "chrome/common/metrics/metrics_log_base.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 // Dummy serializer that just stores logs in memory.
18 class DummyLogSerializer
: public MetricsLogManager::LogSerializer
{
20 virtual void SerializeLogs(
21 const std::vector
<MetricsLogManager::SerializedLog
>& logs
,
22 MetricsLogManager::LogType log_type
) OVERRIDE
{
23 persisted_logs_
[log_type
] = logs
;
26 virtual void DeserializeLogs(
27 MetricsLogManager::LogType log_type
,
28 std::vector
<MetricsLogManager::SerializedLog
>* logs
) OVERRIDE
{
29 ASSERT_NE(static_cast<void*>(NULL
), logs
);
30 *logs
= persisted_logs_
[log_type
];
33 // Returns the number of logs of the given type.
34 size_t TypeCount(MetricsLogManager::LogType log_type
) {
35 return persisted_logs_
[log_type
].size();
38 // In-memory "persitent storage".
39 std::vector
<MetricsLogManager::SerializedLog
> persisted_logs_
[2];
44 TEST(MetricsLogManagerTest
, StandardFlow
) {
45 MetricsLogManager log_manager
;
47 // Make sure a new manager has a clean slate.
48 EXPECT_EQ(NULL
, log_manager
.current_log());
49 EXPECT_FALSE(log_manager
.has_staged_log());
50 EXPECT_FALSE(log_manager
.has_unsent_logs());
52 // Check that the normal flow works.
53 MetricsLogBase
* initial_log
= new MetricsLogBase("id", 0, "version");
54 log_manager
.BeginLoggingWithLog(initial_log
, MetricsLogBase::INITIAL_LOG
);
55 EXPECT_EQ(initial_log
, log_manager
.current_log());
56 EXPECT_FALSE(log_manager
.has_staged_log());
58 log_manager
.FinishCurrentLog();
59 EXPECT_EQ(NULL
, log_manager
.current_log());
60 EXPECT_TRUE(log_manager
.has_unsent_logs());
61 EXPECT_FALSE(log_manager
.has_staged_log());
63 MetricsLogBase
* second_log
= new MetricsLogBase("id", 0, "version");
64 log_manager
.BeginLoggingWithLog(second_log
, MetricsLogBase::ONGOING_LOG
);
65 EXPECT_EQ(second_log
, log_manager
.current_log());
67 log_manager
.StageNextLogForUpload();
68 EXPECT_TRUE(log_manager
.has_staged_log());
69 EXPECT_FALSE(log_manager
.staged_log_text().empty());
71 log_manager
.DiscardStagedLog();
72 EXPECT_EQ(second_log
, log_manager
.current_log());
73 EXPECT_FALSE(log_manager
.has_staged_log());
74 EXPECT_FALSE(log_manager
.has_unsent_logs());
75 EXPECT_TRUE(log_manager
.staged_log_text().empty());
77 EXPECT_FALSE(log_manager
.has_unsent_logs());
80 TEST(MetricsLogManagerTest
, AbandonedLog
) {
81 MetricsLogManager log_manager
;
83 MetricsLogBase
* dummy_log
= new MetricsLogBase("id", 0, "version");
84 log_manager
.BeginLoggingWithLog(dummy_log
, MetricsLogBase::INITIAL_LOG
);
85 EXPECT_EQ(dummy_log
, log_manager
.current_log());
87 log_manager
.DiscardCurrentLog();
88 EXPECT_EQ(NULL
, log_manager
.current_log());
89 EXPECT_FALSE(log_manager
.has_staged_log());
92 TEST(MetricsLogManagerTest
, InterjectedLog
) {
93 MetricsLogManager log_manager
;
95 MetricsLogBase
* ongoing_log
= new MetricsLogBase("id", 0, "version");
96 MetricsLogBase
* temp_log
= new MetricsLogBase("id", 0, "version");
98 log_manager
.BeginLoggingWithLog(ongoing_log
, MetricsLogBase::ONGOING_LOG
);
99 EXPECT_EQ(ongoing_log
, log_manager
.current_log());
101 log_manager
.PauseCurrentLog();
102 EXPECT_EQ(NULL
, log_manager
.current_log());
104 log_manager
.BeginLoggingWithLog(temp_log
, MetricsLogBase::INITIAL_LOG
);
105 EXPECT_EQ(temp_log
, log_manager
.current_log());
106 log_manager
.FinishCurrentLog();
107 EXPECT_EQ(NULL
, log_manager
.current_log());
109 log_manager
.ResumePausedLog();
110 EXPECT_EQ(ongoing_log
, log_manager
.current_log());
112 EXPECT_FALSE(log_manager
.has_staged_log());
113 log_manager
.StageNextLogForUpload();
114 log_manager
.DiscardStagedLog();
115 EXPECT_FALSE(log_manager
.has_unsent_logs());
118 TEST(MetricsLogManagerTest
, InterjectedLogPreservesType
) {
119 MetricsLogManager log_manager
;
120 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
121 log_manager
.set_log_serializer(serializer
);
122 log_manager
.LoadPersistedUnsentLogs();
124 MetricsLogBase
* ongoing_log
= new MetricsLogBase("id", 0, "version");
125 MetricsLogBase
* temp_log
= new MetricsLogBase("id", 0, "version");
127 log_manager
.BeginLoggingWithLog(ongoing_log
, MetricsLogBase::ONGOING_LOG
);
128 log_manager
.PauseCurrentLog();
129 log_manager
.BeginLoggingWithLog(temp_log
, MetricsLogBase::INITIAL_LOG
);
130 log_manager
.FinishCurrentLog();
131 log_manager
.ResumePausedLog();
132 log_manager
.StageNextLogForUpload();
133 log_manager
.DiscardStagedLog();
135 // Verify that the remaining log (which is the original ongoing log) still
136 // has the right type.
137 log_manager
.FinishCurrentLog();
138 log_manager
.PersistUnsentLogs();
139 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
140 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
143 TEST(MetricsLogManagerTest
, StoreAndLoad
) {
144 std::vector
<MetricsLogManager::SerializedLog
> initial_logs
;
145 std::vector
<MetricsLogManager::SerializedLog
> ongoing_logs
;
147 // Set up some in-progress logging in a scoped log manager simulating the
148 // leadup to quitting, then persist as would be done on quit.
150 MetricsLogManager log_manager
;
151 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
152 log_manager
.set_log_serializer(serializer
);
153 log_manager
.LoadPersistedUnsentLogs();
155 // Simulate a log having already been unsent from a previous session.
156 MetricsLogManager::SerializedLog log
;
157 std::string text
= "proto";
158 log
.SwapLogText(&text
);
159 serializer
->persisted_logs_
[MetricsLogBase::ONGOING_LOG
].push_back(log
);
160 EXPECT_FALSE(log_manager
.has_unsent_logs());
161 log_manager
.LoadPersistedUnsentLogs();
162 EXPECT_TRUE(log_manager
.has_unsent_logs());
164 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
165 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
166 log_manager
.BeginLoggingWithLog(log1
, MetricsLogBase::INITIAL_LOG
);
167 log_manager
.FinishCurrentLog();
168 log_manager
.BeginLoggingWithLog(log2
, MetricsLogBase::ONGOING_LOG
);
169 log_manager
.StageNextLogForUpload();
170 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
171 log_manager
.FinishCurrentLog();
173 // Nothing should be written out until PersistUnsentLogs is called.
174 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
175 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
176 log_manager
.PersistUnsentLogs();
177 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
178 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
180 // Save the logs to transfer over to a new serializer (since log_manager
181 // owns |serializer|, so it's about to go away.
182 initial_logs
= serializer
->persisted_logs_
[MetricsLogBase::INITIAL_LOG
];
183 ongoing_logs
= serializer
->persisted_logs_
[MetricsLogBase::ONGOING_LOG
];
186 // Now simulate the relaunch, ensure that the log manager restores
187 // everything correctly, and verify that once the are handled they are not
190 MetricsLogManager log_manager
;
192 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
193 serializer
->persisted_logs_
[MetricsLogBase::INITIAL_LOG
] = initial_logs
;
194 serializer
->persisted_logs_
[MetricsLogBase::ONGOING_LOG
] = ongoing_logs
;
196 log_manager
.set_log_serializer(serializer
);
197 log_manager
.LoadPersistedUnsentLogs();
198 EXPECT_TRUE(log_manager
.has_unsent_logs());
200 log_manager
.StageNextLogForUpload();
201 log_manager
.DiscardStagedLog();
202 // The initial log should be sent first; update the persisted storage to
204 log_manager
.PersistUnsentLogs();
205 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
206 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
208 // Handle the first ongoing log.
209 log_manager
.StageNextLogForUpload();
210 log_manager
.DiscardStagedLog();
211 EXPECT_TRUE(log_manager
.has_unsent_logs());
213 // Handle the last log.
214 log_manager
.StageNextLogForUpload();
215 log_manager
.DiscardStagedLog();
216 EXPECT_FALSE(log_manager
.has_unsent_logs());
218 // Nothing should have changed "on disk" since PersistUnsentLogs hasn't been
220 EXPECT_EQ(2U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
221 // Persist, and make sure nothing is left.
222 log_manager
.PersistUnsentLogs();
223 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
224 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
228 TEST(MetricsLogManagerTest
, StoreStagedLogTypes
) {
229 // Ensure that types are preserved when storing staged logs.
231 MetricsLogManager log_manager
;
232 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
233 log_manager
.set_log_serializer(serializer
);
234 log_manager
.LoadPersistedUnsentLogs();
236 MetricsLogBase
* log
= new MetricsLogBase("id", 0, "version");
237 log_manager
.BeginLoggingWithLog(log
, MetricsLogBase::ONGOING_LOG
);
238 log_manager
.FinishCurrentLog();
239 log_manager
.StageNextLogForUpload();
240 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
241 log_manager
.PersistUnsentLogs();
243 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
244 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
248 MetricsLogManager log_manager
;
249 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
250 log_manager
.set_log_serializer(serializer
);
251 log_manager
.LoadPersistedUnsentLogs();
253 MetricsLogBase
* log
= new MetricsLogBase("id", 0, "version");
254 log_manager
.BeginLoggingWithLog(log
, MetricsLogBase::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(MetricsLogBase::INITIAL_LOG
));
261 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
265 TEST(MetricsLogManagerTest
, LargeLogDiscarding
) {
266 MetricsLogManager log_manager
;
267 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
268 log_manager
.set_log_serializer(serializer
);
269 log_manager
.LoadPersistedUnsentLogs();
271 // Set the size threshold very low, to verify that it's honored.
272 log_manager
.set_max_ongoing_log_store_size(1);
274 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
275 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
276 log_manager
.BeginLoggingWithLog(log1
, MetricsLogBase::INITIAL_LOG
);
277 log_manager
.FinishCurrentLog();
278 log_manager
.BeginLoggingWithLog(log2
, MetricsLogBase::ONGOING_LOG
);
279 log_manager
.FinishCurrentLog();
281 // Only the ongoing log should be written out, due to the threshold.
282 log_manager
.PersistUnsentLogs();
283 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
284 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
287 TEST(MetricsLogManagerTest
, ProvisionalStoreStandardFlow
) {
288 // Ensure that provisional store works, and discards the correct log.
290 MetricsLogManager log_manager
;
291 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
292 log_manager
.set_log_serializer(serializer
);
293 log_manager
.LoadPersistedUnsentLogs();
295 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
296 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
297 log_manager
.BeginLoggingWithLog(log1
, MetricsLogBase::INITIAL_LOG
);
298 log_manager
.FinishCurrentLog();
299 log_manager
.BeginLoggingWithLog(log2
, MetricsLogBase::ONGOING_LOG
);
300 log_manager
.StageNextLogForUpload();
301 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
302 log_manager
.FinishCurrentLog();
303 log_manager
.DiscardLastProvisionalStore();
305 log_manager
.PersistUnsentLogs();
306 EXPECT_EQ(0U, serializer
->TypeCount(MetricsLogBase::INITIAL_LOG
));
307 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
311 TEST(MetricsLogManagerTest
, ProvisionalStoreNoop
) {
312 // Ensure that trying to drop a sent log is a no-op, even if another log has
313 // since been staged.
315 MetricsLogManager log_manager
;
316 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
317 log_manager
.set_log_serializer(serializer
);
318 log_manager
.LoadPersistedUnsentLogs();
320 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
321 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
322 log_manager
.BeginLoggingWithLog(log1
, MetricsLogBase::ONGOING_LOG
);
323 log_manager
.FinishCurrentLog();
324 log_manager
.StageNextLogForUpload();
325 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
326 log_manager
.StageNextLogForUpload();
327 log_manager
.DiscardStagedLog();
328 log_manager
.BeginLoggingWithLog(log2
, MetricsLogBase::ONGOING_LOG
);
329 log_manager
.FinishCurrentLog();
330 log_manager
.StageNextLogForUpload();
331 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
332 log_manager
.DiscardLastProvisionalStore();
334 log_manager
.PersistUnsentLogs();
335 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
338 // Ensure that trying to drop more than once is a no-op
340 MetricsLogManager log_manager
;
341 DummyLogSerializer
* serializer
= new DummyLogSerializer
;
342 log_manager
.set_log_serializer(serializer
);
343 log_manager
.LoadPersistedUnsentLogs();
345 MetricsLogBase
* log1
= new MetricsLogBase("id", 0, "version");
346 MetricsLogBase
* log2
= new MetricsLogBase("id", 0, "version");
347 log_manager
.BeginLoggingWithLog(log1
, MetricsLogBase::ONGOING_LOG
);
348 log_manager
.FinishCurrentLog();
349 log_manager
.StageNextLogForUpload();
350 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE
);
351 log_manager
.BeginLoggingWithLog(log2
, MetricsLogBase::ONGOING_LOG
);
352 log_manager
.FinishCurrentLog();
353 log_manager
.StageNextLogForUpload();
354 log_manager
.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE
);
355 log_manager
.DiscardLastProvisionalStore();
356 log_manager
.DiscardLastProvisionalStore();
358 log_manager
.PersistUnsentLogs();
359 EXPECT_EQ(1U, serializer
->TypeCount(MetricsLogBase::ONGOING_LOG
));
363 TEST(MetricsLogManagerTest
, SerializedLog
) {
364 const char kFooText
[] = "foo";
365 const std::string foo_hash
= base::SHA1HashString(kFooText
);
366 const char kBarText
[] = "bar";
367 const std::string bar_hash
= base::SHA1HashString(kBarText
);
369 MetricsLogManager::SerializedLog log
;
370 EXPECT_TRUE(log
.log_text().empty());
371 EXPECT_TRUE(log
.log_hash().empty());
373 std::string foo
= kFooText
;
374 log
.SwapLogText(&foo
);
375 EXPECT_TRUE(foo
.empty());
376 EXPECT_FALSE(log
.IsEmpty());
377 EXPECT_EQ(kFooText
, log
.log_text());
378 EXPECT_EQ(foo_hash
, log
.log_hash());
380 std::string bar
= kBarText
;
381 log
.SwapLogText(&bar
);
382 EXPECT_EQ(kFooText
, bar
);
383 EXPECT_FALSE(log
.IsEmpty());
384 EXPECT_EQ(kBarText
, log
.log_text());
385 EXPECT_EQ(bar_hash
, log
.log_hash());
388 EXPECT_TRUE(log
.IsEmpty());
389 EXPECT_TRUE(log
.log_text().empty());
390 EXPECT_TRUE(log
.log_hash().empty());
392 MetricsLogManager::SerializedLog log2
;
394 log2
.SwapLogText(&foo
);
396 EXPECT_FALSE(log
.IsEmpty());
397 EXPECT_EQ(kFooText
, log
.log_text());
398 EXPECT_EQ(foo_hash
, log
.log_hash());
399 EXPECT_TRUE(log2
.IsEmpty());
400 EXPECT_TRUE(log2
.log_text().empty());
401 EXPECT_TRUE(log2
.log_hash().empty());