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 "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