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