Home | History | Annotate | Download | only in metrics
      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