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