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 <string> 6 #include <utility> 7 #include <vector> 8 9 #include "chrome/common/metrics/metrics_log_base.h" 10 #include "chrome/common/metrics/metrics_log_manager.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 namespace { 14 15 class MetricsLogManagerTest : public testing::Test { 16 }; 17 18 // Dummy serializer that just stores logs in memory. 19 class DummyLogSerializer : public MetricsLogManager::LogSerializer { 20 public: 21 virtual void SerializeLogs(const std::vector<std::string>& logs, 22 MetricsLogManager::LogType log_type) OVERRIDE { 23 persisted_logs_[log_type] = logs; 24 } 25 26 virtual void DeserializeLogs(MetricsLogManager::LogType log_type, 27 std::vector<std::string>* logs) OVERRIDE { 28 ASSERT_NE(static_cast<void*>(NULL), logs); 29 *logs = persisted_logs_[log_type]; 30 } 31 32 // Returns the number of logs of the given type. 33 size_t TypeCount(MetricsLogManager::LogType log_type) { 34 return persisted_logs_[log_type].size(); 35 } 36 37 // In-memory "persitent storage". 38 std::vector<std::string> persisted_logs_[2]; 39 }; 40 41 } // namespace 42 43 TEST(MetricsLogManagerTest, StandardFlow) { 44 MetricsLogManager log_manager; 45 46 // Make sure a new manager has a clean slate. 47 EXPECT_EQ(NULL, log_manager.current_log()); 48 EXPECT_FALSE(log_manager.has_staged_log()); 49 EXPECT_FALSE(log_manager.has_unsent_logs()); 50 51 // Check that the normal flow works. 52 MetricsLogBase* initial_log = new MetricsLogBase("id", 0, "version"); 53 log_manager.BeginLoggingWithLog(initial_log, MetricsLogManager::INITIAL_LOG); 54 EXPECT_EQ(initial_log, log_manager.current_log()); 55 EXPECT_FALSE(log_manager.has_staged_log()); 56 57 log_manager.FinishCurrentLog(); 58 EXPECT_EQ(NULL, log_manager.current_log()); 59 EXPECT_TRUE(log_manager.has_unsent_logs()); 60 EXPECT_FALSE(log_manager.has_staged_log()); 61 62 MetricsLogBase* second_log = new MetricsLogBase("id", 0, "version"); 63 log_manager.BeginLoggingWithLog(second_log, MetricsLogManager::ONGOING_LOG); 64 EXPECT_EQ(second_log, log_manager.current_log()); 65 66 log_manager.StageNextLogForUpload(); 67 EXPECT_TRUE(log_manager.has_staged_log()); 68 EXPECT_FALSE(log_manager.staged_log_text().empty()); 69 70 log_manager.DiscardStagedLog(); 71 EXPECT_EQ(second_log, log_manager.current_log()); 72 EXPECT_FALSE(log_manager.has_staged_log()); 73 EXPECT_FALSE(log_manager.has_unsent_logs()); 74 EXPECT_TRUE(log_manager.staged_log_text().empty()); 75 76 EXPECT_FALSE(log_manager.has_unsent_logs()); 77 } 78 79 TEST(MetricsLogManagerTest, AbandonedLog) { 80 MetricsLogManager log_manager; 81 82 MetricsLogBase* dummy_log = new MetricsLogBase("id", 0, "version"); 83 log_manager.BeginLoggingWithLog(dummy_log, MetricsLogManager::INITIAL_LOG); 84 EXPECT_EQ(dummy_log, log_manager.current_log()); 85 86 log_manager.DiscardCurrentLog(); 87 EXPECT_EQ(NULL, log_manager.current_log()); 88 EXPECT_FALSE(log_manager.has_staged_log()); 89 } 90 91 TEST(MetricsLogManagerTest, InterjectedLog) { 92 MetricsLogManager log_manager; 93 94 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); 95 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); 96 97 log_manager.BeginLoggingWithLog(ongoing_log, MetricsLogManager::ONGOING_LOG); 98 EXPECT_EQ(ongoing_log, log_manager.current_log()); 99 100 log_manager.PauseCurrentLog(); 101 EXPECT_EQ(NULL, log_manager.current_log()); 102 103 log_manager.BeginLoggingWithLog(temp_log, MetricsLogManager::INITIAL_LOG); 104 EXPECT_EQ(temp_log, log_manager.current_log()); 105 log_manager.FinishCurrentLog(); 106 EXPECT_EQ(NULL, log_manager.current_log()); 107 108 log_manager.ResumePausedLog(); 109 EXPECT_EQ(ongoing_log, log_manager.current_log()); 110 111 EXPECT_FALSE(log_manager.has_staged_log()); 112 log_manager.StageNextLogForUpload(); 113 log_manager.DiscardStagedLog(); 114 EXPECT_FALSE(log_manager.has_unsent_logs()); 115 } 116 117 TEST(MetricsLogManagerTest, InterjectedLogPreservesType) { 118 MetricsLogManager log_manager; 119 120 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); 121 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); 122 123 log_manager.BeginLoggingWithLog(ongoing_log, MetricsLogManager::ONGOING_LOG); 124 log_manager.PauseCurrentLog(); 125 log_manager.BeginLoggingWithLog(temp_log, MetricsLogManager::INITIAL_LOG); 126 log_manager.FinishCurrentLog(); 127 log_manager.ResumePausedLog(); 128 log_manager.StageNextLogForUpload(); 129 log_manager.DiscardStagedLog(); 130 131 // Verify that the remaining log (which is the original ongoing log) still 132 // has the right type. 133 DummyLogSerializer* serializer = new DummyLogSerializer; 134 log_manager.set_log_serializer(serializer); 135 log_manager.FinishCurrentLog(); 136 log_manager.PersistUnsentLogs(); 137 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 138 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 139 } 140 141 TEST(MetricsLogManagerTest, StoreAndLoad) { 142 std::vector<std::string> initial_logs; 143 std::vector<std::string> ongoing_logs; 144 145 // Set up some in-progress logging in a scoped log manager simulating the 146 // leadup to quitting, then persist as would be done on quit. 147 { 148 MetricsLogManager log_manager; 149 DummyLogSerializer* serializer = new DummyLogSerializer; 150 log_manager.set_log_serializer(serializer); 151 // Simulate a log having already been unsent from a previous session. 152 std::string log = "proto"; 153 serializer->persisted_logs_[MetricsLogManager::ONGOING_LOG].push_back(log); 154 EXPECT_FALSE(log_manager.has_unsent_logs()); 155 log_manager.LoadPersistedUnsentLogs(); 156 EXPECT_TRUE(log_manager.has_unsent_logs()); 157 158 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); 159 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); 160 log_manager.BeginLoggingWithLog(log1, MetricsLogManager::INITIAL_LOG); 161 log_manager.FinishCurrentLog(); 162 log_manager.BeginLoggingWithLog(log2, MetricsLogManager::ONGOING_LOG); 163 log_manager.StageNextLogForUpload(); 164 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); 165 log_manager.FinishCurrentLog(); 166 167 // Nothing should be written out until PersistUnsentLogs is called. 168 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 169 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 170 log_manager.PersistUnsentLogs(); 171 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 172 EXPECT_EQ(2U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 173 174 // Save the logs to transfer over to a new serializer (since log_manager 175 // owns |serializer|, so it's about to go away. 176 initial_logs = serializer->persisted_logs_[MetricsLogManager::INITIAL_LOG]; 177 ongoing_logs = serializer->persisted_logs_[MetricsLogManager::ONGOING_LOG]; 178 } 179 180 // Now simulate the relaunch, ensure that the log manager restores 181 // everything correctly, and verify that once the are handled they are not 182 // re-persisted. 183 { 184 MetricsLogManager log_manager; 185 186 DummyLogSerializer* serializer = new DummyLogSerializer; 187 serializer->persisted_logs_[MetricsLogManager::INITIAL_LOG] = initial_logs; 188 serializer->persisted_logs_[MetricsLogManager::ONGOING_LOG] = ongoing_logs; 189 190 log_manager.set_log_serializer(serializer); 191 log_manager.LoadPersistedUnsentLogs(); 192 EXPECT_TRUE(log_manager.has_unsent_logs()); 193 194 log_manager.StageNextLogForUpload(); 195 log_manager.DiscardStagedLog(); 196 // The initial log should be sent first; update the persisted storage to 197 // verify. 198 log_manager.PersistUnsentLogs(); 199 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 200 EXPECT_EQ(2U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 201 202 // Handle the first ongoing log. 203 log_manager.StageNextLogForUpload(); 204 log_manager.DiscardStagedLog(); 205 EXPECT_TRUE(log_manager.has_unsent_logs()); 206 207 // Handle the last log. 208 log_manager.StageNextLogForUpload(); 209 log_manager.DiscardStagedLog(); 210 EXPECT_FALSE(log_manager.has_unsent_logs()); 211 212 // Nothing should have changed "on disk" since PersistUnsentLogs hasn't been 213 // called again. 214 EXPECT_EQ(2U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 215 // Persist, and make sure nothing is left. 216 log_manager.PersistUnsentLogs(); 217 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 218 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 219 } 220 } 221 222 TEST(MetricsLogManagerTest, StoreStagedLogTypes) { 223 // Ensure that types are preserved when storing staged logs. 224 { 225 MetricsLogManager log_manager; 226 DummyLogSerializer* serializer = new DummyLogSerializer; 227 log_manager.set_log_serializer(serializer); 228 229 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); 230 log_manager.BeginLoggingWithLog(log, MetricsLogManager::ONGOING_LOG); 231 log_manager.FinishCurrentLog(); 232 log_manager.StageNextLogForUpload(); 233 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); 234 log_manager.PersistUnsentLogs(); 235 236 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 237 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 238 } 239 240 { 241 MetricsLogManager log_manager; 242 DummyLogSerializer* serializer = new DummyLogSerializer; 243 log_manager.set_log_serializer(serializer); 244 245 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); 246 log_manager.BeginLoggingWithLog(log, MetricsLogManager::INITIAL_LOG); 247 log_manager.FinishCurrentLog(); 248 log_manager.StageNextLogForUpload(); 249 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); 250 log_manager.PersistUnsentLogs(); 251 252 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 253 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 254 } 255 } 256 257 TEST(MetricsLogManagerTest, LargeLogDiscarding) { 258 MetricsLogManager log_manager; 259 DummyLogSerializer* serializer = new DummyLogSerializer; 260 log_manager.set_log_serializer(serializer); 261 // Set the size threshold very low, to verify that it's honored. 262 log_manager.set_max_ongoing_log_store_size(1); 263 264 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); 265 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); 266 log_manager.BeginLoggingWithLog(log1, MetricsLogManager::INITIAL_LOG); 267 log_manager.FinishCurrentLog(); 268 log_manager.BeginLoggingWithLog(log2, MetricsLogManager::ONGOING_LOG); 269 log_manager.FinishCurrentLog(); 270 271 // Only the ongoing log should be written out, due to the threshold. 272 log_manager.PersistUnsentLogs(); 273 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 274 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 275 } 276 277 TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) { 278 // Ensure that provisional store works, and discards the correct log. 279 { 280 MetricsLogManager log_manager; 281 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); 282 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); 283 log_manager.BeginLoggingWithLog(log1, MetricsLogManager::INITIAL_LOG); 284 log_manager.FinishCurrentLog(); 285 log_manager.BeginLoggingWithLog(log2, MetricsLogManager::ONGOING_LOG); 286 log_manager.StageNextLogForUpload(); 287 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); 288 log_manager.FinishCurrentLog(); 289 log_manager.DiscardLastProvisionalStore(); 290 291 DummyLogSerializer* serializer = new DummyLogSerializer; 292 log_manager.set_log_serializer(serializer); 293 log_manager.PersistUnsentLogs(); 294 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogManager::INITIAL_LOG)); 295 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 296 } 297 } 298 299 TEST(MetricsLogManagerTest, ProvisionalStoreNoop) { 300 // Ensure that trying to drop a sent log is a no-op, even if another log has 301 // since been staged. 302 { 303 MetricsLogManager log_manager; 304 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); 305 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); 306 log_manager.BeginLoggingWithLog(log1, MetricsLogManager::ONGOING_LOG); 307 log_manager.FinishCurrentLog(); 308 log_manager.StageNextLogForUpload(); 309 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); 310 log_manager.StageNextLogForUpload(); 311 log_manager.DiscardStagedLog(); 312 log_manager.BeginLoggingWithLog(log2, MetricsLogManager::ONGOING_LOG); 313 log_manager.FinishCurrentLog(); 314 log_manager.StageNextLogForUpload(); 315 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); 316 log_manager.DiscardLastProvisionalStore(); 317 318 DummyLogSerializer* serializer = new DummyLogSerializer; 319 log_manager.set_log_serializer(serializer); 320 log_manager.PersistUnsentLogs(); 321 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 322 } 323 324 // Ensure that trying to drop more than once is a no-op 325 { 326 MetricsLogManager log_manager; 327 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); 328 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); 329 log_manager.BeginLoggingWithLog(log1, MetricsLogManager::ONGOING_LOG); 330 log_manager.FinishCurrentLog(); 331 log_manager.StageNextLogForUpload(); 332 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); 333 log_manager.BeginLoggingWithLog(log2, MetricsLogManager::ONGOING_LOG); 334 log_manager.FinishCurrentLog(); 335 log_manager.StageNextLogForUpload(); 336 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); 337 log_manager.DiscardLastProvisionalStore(); 338 log_manager.DiscardLastProvisionalStore(); 339 340 DummyLogSerializer* serializer = new DummyLogSerializer; 341 log_manager.set_log_serializer(serializer); 342 log_manager.PersistUnsentLogs(); 343 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogManager::ONGOING_LOG)); 344 } 345 } 346