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: 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. 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 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 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 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 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 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 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 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 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 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