• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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