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. 4 5 #include "chrome/common/metrics/metrics_log_manager.h" 6 7 #include <string> 8 #include <utility> 9 #include <vector> 10 11 #include "base/sha1.h" 12 #include "chrome/common/metrics/metrics_log_base.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace { 16 17 // Dummy serializer that just stores logs in memory. 18 class DummyLogSerializer : public MetricsLogManager::LogSerializer { 19 public: 20 virtual void SerializeLogs( 21 const std::vector<MetricsLogManager::SerializedLog>& logs, 22 MetricsLogManager::LogType log_type) OVERRIDE { 23 persisted_logs_[log_type] = logs; 24 } 25 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]; 31 } 32 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(); 36 } 37 38 // In-memory "persitent storage". 39 std::vector<MetricsLogManager::SerializedLog> persisted_logs_[2]; 40 }; 41 42 } // namespace 43 44 TEST(MetricsLogManagerTest, StandardFlow) { 45 MetricsLogManager log_manager; 46 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()); 51 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()); 57 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()); 62 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()); 66 67 log_manager.StageNextLogForUpload(); 68 EXPECT_TRUE(log_manager.has_staged_log()); 69 EXPECT_FALSE(log_manager.staged_log_text().empty()); 70 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()); 76 77 EXPECT_FALSE(log_manager.has_unsent_logs()); 78 } 79 80 TEST(MetricsLogManagerTest, AbandonedLog) { 81 MetricsLogManager log_manager; 82 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()); 86 87 log_manager.DiscardCurrentLog(); 88 EXPECT_EQ(NULL, log_manager.current_log()); 89 EXPECT_FALSE(log_manager.has_staged_log()); 90 } 91 92 TEST(MetricsLogManagerTest, InterjectedLog) { 93 MetricsLogManager log_manager; 94 95 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); 96 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); 97 98 log_manager.BeginLoggingWithLog(ongoing_log, MetricsLogBase::ONGOING_LOG); 99 EXPECT_EQ(ongoing_log, log_manager.current_log()); 100 101 log_manager.PauseCurrentLog(); 102 EXPECT_EQ(NULL, log_manager.current_log()); 103 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()); 108 109 log_manager.ResumePausedLog(); 110 EXPECT_EQ(ongoing_log, log_manager.current_log()); 111 112 EXPECT_FALSE(log_manager.has_staged_log()); 113 log_manager.StageNextLogForUpload(); 114 log_manager.DiscardStagedLog(); 115 EXPECT_FALSE(log_manager.has_unsent_logs()); 116 } 117 118 TEST(MetricsLogManagerTest, InterjectedLogPreservesType) { 119 MetricsLogManager log_manager; 120 DummyLogSerializer* serializer = new DummyLogSerializer; 121 log_manager.set_log_serializer(serializer); 122 log_manager.LoadPersistedUnsentLogs(); 123 124 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); 125 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); 126 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(); 134 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)); 141 } 142 143 TEST(MetricsLogManagerTest, StoreAndLoad) { 144 std::vector<MetricsLogManager::SerializedLog> initial_logs; 145 std::vector<MetricsLogManager::SerializedLog> ongoing_logs; 146 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. 149 { 150 MetricsLogManager log_manager; 151 DummyLogSerializer* serializer = new DummyLogSerializer; 152 log_manager.set_log_serializer(serializer); 153 log_manager.LoadPersistedUnsentLogs(); 154 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()); 163 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(); 172 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)); 179 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]; 184 } 185 186 // Now simulate the relaunch, ensure that the log manager restores 187 // everything correctly, and verify that once the are handled they are not 188 // re-persisted. 189 { 190 MetricsLogManager log_manager; 191 192 DummyLogSerializer* serializer = new DummyLogSerializer; 193 serializer->persisted_logs_[MetricsLogBase::INITIAL_LOG] = initial_logs; 194 serializer->persisted_logs_[MetricsLogBase::ONGOING_LOG] = ongoing_logs; 195 196 log_manager.set_log_serializer(serializer); 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, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); 206 EXPECT_EQ(2U, serializer->TypeCount(MetricsLogBase::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, 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)); 225 } 226 } 227 228 TEST(MetricsLogManagerTest, StoreStagedLogTypes) { 229 // Ensure that types are preserved when storing staged logs. 230 { 231 MetricsLogManager log_manager; 232 DummyLogSerializer* serializer = new DummyLogSerializer; 233 log_manager.set_log_serializer(serializer); 234 log_manager.LoadPersistedUnsentLogs(); 235 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(); 242 243 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); 244 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); 245 } 246 247 { 248 MetricsLogManager log_manager; 249 DummyLogSerializer* serializer = new DummyLogSerializer; 250 log_manager.set_log_serializer(serializer); 251 log_manager.LoadPersistedUnsentLogs(); 252 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(); 259 260 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); 261 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); 262 } 263 } 264 265 TEST(MetricsLogManagerTest, LargeLogDiscarding) { 266 MetricsLogManager log_manager; 267 DummyLogSerializer* serializer = new DummyLogSerializer; 268 log_manager.set_log_serializer(serializer); 269 log_manager.LoadPersistedUnsentLogs(); 270 271 // Set the size threshold very low, to verify that it's honored. 272 log_manager.set_max_ongoing_log_store_size(1); 273 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(); 280 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)); 285 } 286 287 TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) { 288 // Ensure that provisional store works, and discards the correct log. 289 { 290 MetricsLogManager log_manager; 291 DummyLogSerializer* serializer = new DummyLogSerializer; 292 log_manager.set_log_serializer(serializer); 293 log_manager.LoadPersistedUnsentLogs(); 294 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(); 304 305 log_manager.PersistUnsentLogs(); 306 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); 307 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); 308 } 309 } 310 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. 314 { 315 MetricsLogManager log_manager; 316 DummyLogSerializer* serializer = new DummyLogSerializer; 317 log_manager.set_log_serializer(serializer); 318 log_manager.LoadPersistedUnsentLogs(); 319 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(); 333 334 log_manager.PersistUnsentLogs(); 335 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); 336 } 337 338 // Ensure that trying to drop more than once is a no-op 339 { 340 MetricsLogManager log_manager; 341 DummyLogSerializer* serializer = new DummyLogSerializer; 342 log_manager.set_log_serializer(serializer); 343 log_manager.LoadPersistedUnsentLogs(); 344 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(); 357 358 log_manager.PersistUnsentLogs(); 359 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); 360 } 361 } 362 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); 368 369 MetricsLogManager::SerializedLog log; 370 EXPECT_TRUE(log.log_text().empty()); 371 EXPECT_TRUE(log.log_hash().empty()); 372 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()); 379 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()); 386 387 log.Clear(); 388 EXPECT_TRUE(log.IsEmpty()); 389 EXPECT_TRUE(log.log_text().empty()); 390 EXPECT_TRUE(log.log_hash().empty()); 391 392 MetricsLogManager::SerializedLog log2; 393 foo = kFooText; 394 log2.SwapLogText(&foo); 395 log.Swap(&log2); 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()); 402 } 403