Home | History | Annotate | Download | only in core
      1 // Copyright 2013 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/precache/core/precache_database.h"
      6 
      7 #include <map>
      8 
      9 #include "base/files/file_path.h"
     10 #include "base/files/scoped_temp_dir.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/metrics/histogram_samples.h"
     14 #include "base/metrics/statistics_recorder.h"
     15 #include "base/time/time.h"
     16 #include "sql/connection.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "url/gurl.h"
     19 
     20 namespace {
     21 
     22 const GURL kURL("http://url.com");
     23 const base::Time kFetchTime = base::Time() + base::TimeDelta::FromHours(1000);
     24 const base::Time kOldFetchTime = kFetchTime - base::TimeDelta::FromDays(1);
     25 const int64 kSize = 5000;
     26 
     27 const char* kHistogramNames[] = {"Precache.DownloadedPrecacheMotivated",
     28                                  "Precache.DownloadedNonPrecache",
     29                                  "Precache.DownloadedNonPrecache.Cellular",
     30                                  "Precache.Saved",
     31                                  "Precache.Saved.Cellular"};
     32 
     33 scoped_ptr<base::HistogramSamples> GetHistogramSamples(
     34     const char* histogram_name) {
     35   base::HistogramBase* histogram =
     36       base::StatisticsRecorder::FindHistogram(histogram_name);
     37 
     38   EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram);
     39 
     40   return histogram->SnapshotSamples().Pass();
     41 }
     42 
     43 std::map<GURL, base::Time> BuildURLTableMap(const GURL& url,
     44                                             const base::Time& precache_time) {
     45   std::map<GURL, base::Time> url_table_map;
     46   url_table_map[url] = precache_time;
     47   return url_table_map;
     48 }
     49 
     50 }  // namespace
     51 
     52 namespace precache {
     53 
     54 class PrecacheDatabaseTest : public testing::Test {
     55  public:
     56   PrecacheDatabaseTest() {}
     57   virtual ~PrecacheDatabaseTest() {}
     58 
     59  protected:
     60   virtual void SetUp() OVERRIDE {
     61     base::StatisticsRecorder::Initialize();
     62     precache_database_ = new PrecacheDatabase();
     63 
     64     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
     65     base::FilePath db_path = scoped_temp_dir_.path().Append(
     66         base::FilePath(FILE_PATH_LITERAL("precache_database")));
     67     precache_database_->Init(db_path);
     68 
     69     // Log a sample for each histogram, to ensure that they are all created.
     70     // This has to be done here, and not in the for loop below, because of the
     71     // way that UMA_HISTOGRAM_COUNTS uses static variables.
     72     UMA_HISTOGRAM_COUNTS("Precache.DownloadedPrecacheMotivated", 0);
     73     UMA_HISTOGRAM_COUNTS("Precache.DownloadedNonPrecache", 0);
     74     UMA_HISTOGRAM_COUNTS("Precache.DownloadedNonPrecache.Cellular", 0);
     75     UMA_HISTOGRAM_COUNTS("Precache.Saved", 0);
     76     UMA_HISTOGRAM_COUNTS("Precache.Saved.Cellular", 0);
     77 
     78     for (size_t i = 0; i < arraysize(kHistogramNames); i++) {
     79       initial_histogram_samples_[i] =
     80           GetHistogramSamples(kHistogramNames[i]).Pass();
     81       initial_histogram_samples_map_[kHistogramNames[i]] =
     82           initial_histogram_samples_[i].get();
     83     }
     84   }
     85 
     86   std::map<GURL, base::Time> GetActualURLTableMap() {
     87     // Flush any buffered writes so that the URL table will be up to date.
     88     precache_database_->Flush();
     89 
     90     std::map<GURL, base::Time> url_table_map;
     91     precache_url_table()->GetAllDataForTesting(&url_table_map);
     92     return url_table_map;
     93   }
     94 
     95   PrecacheURLTable* precache_url_table() {
     96     return &precache_database_->precache_url_table_;
     97   }
     98 
     99   scoped_ptr<base::HistogramSamples> GetHistogramSamplesDelta(
    100       const char* histogram_name) {
    101     scoped_ptr<base::HistogramSamples> delta_samples(
    102         GetHistogramSamples(histogram_name));
    103     delta_samples->Subtract(*initial_histogram_samples_map_[histogram_name]);
    104 
    105     return delta_samples.Pass();
    106   }
    107 
    108   void ExpectNewSample(const char* histogram_name,
    109                        base::HistogramBase::Sample sample) {
    110     scoped_ptr<base::HistogramSamples> delta_samples(
    111         GetHistogramSamplesDelta(histogram_name));
    112     EXPECT_EQ(1, delta_samples->TotalCount());
    113     EXPECT_EQ(1, delta_samples->GetCount(sample));
    114   }
    115 
    116   void ExpectNoNewSamples(const char* histogram_name) {
    117     scoped_ptr<base::HistogramSamples> delta_samples(
    118         GetHistogramSamplesDelta(histogram_name));
    119     EXPECT_EQ(0, delta_samples->TotalCount());
    120   }
    121 
    122   // Convenience methods for recording different types of URL fetches. These
    123   // exist to improve the readability of the tests.
    124   void RecordPrecacheFromNetwork(const GURL& url, const base::Time& fetch_time,
    125                                  int64 size);
    126   void RecordPrecacheFromCache(const GURL& url, const base::Time& fetch_time,
    127                                int64 size);
    128   void RecordFetchFromNetwork(const GURL& url, const base::Time& fetch_time,
    129                               int64 size);
    130   void RecordFetchFromNetworkCellular(const GURL& url,
    131                                       const base::Time& fetch_time, int64 size);
    132   void RecordFetchFromCache(const GURL& url, const base::Time& fetch_time,
    133                             int64 size);
    134   void RecordFetchFromCacheCellular(const GURL& url,
    135                                     const base::Time& fetch_time, int64 size);
    136 
    137   // Having this MessageLoop member variable causes base::MessageLoop::current()
    138   // to be set properly.
    139   base::MessageLoopForUI loop_;
    140 
    141   scoped_refptr<PrecacheDatabase> precache_database_;
    142   base::ScopedTempDir scoped_temp_dir_;
    143   scoped_ptr<base::HistogramSamples> initial_histogram_samples_
    144       [arraysize(kHistogramNames)];
    145   std::map<std::string, base::HistogramSamples*> initial_histogram_samples_map_;
    146 };
    147 
    148 void PrecacheDatabaseTest::RecordPrecacheFromNetwork(
    149     const GURL& url, const base::Time& fetch_time, int64 size) {
    150   precache_database_->RecordURLPrecached(url, fetch_time, size,
    151                                          false /* was_cached */);
    152 }
    153 
    154 void PrecacheDatabaseTest::RecordPrecacheFromCache(const GURL& url,
    155                                                    const base::Time& fetch_time,
    156                                                    int64 size) {
    157   precache_database_->RecordURLPrecached(url, fetch_time, size,
    158                                          true /* was_cached */);
    159 }
    160 
    161 void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL& url,
    162                                                   const base::Time& fetch_time,
    163                                                   int64 size) {
    164   precache_database_->RecordURLFetched(url, fetch_time, size,
    165                                        false /* was_cached */,
    166                                        false /* is_connection_cellular */);
    167 }
    168 
    169 void PrecacheDatabaseTest::RecordFetchFromNetworkCellular(
    170     const GURL& url, const base::Time& fetch_time, int64 size) {
    171   precache_database_->RecordURLFetched(url, fetch_time, size,
    172                                        false /* was_cached */,
    173                                        true /* is_connection_cellular */);
    174 }
    175 
    176 void PrecacheDatabaseTest::RecordFetchFromCache(const GURL& url,
    177                                                 const base::Time& fetch_time,
    178                                                 int64 size) {
    179   precache_database_->RecordURLFetched(url, fetch_time, size,
    180                                        true /* was_cached */,
    181                                        false /* is_connection_cellular */);
    182 }
    183 
    184 void PrecacheDatabaseTest::RecordFetchFromCacheCellular(
    185     const GURL& url, const base::Time& fetch_time, int64 size) {
    186   precache_database_->RecordURLFetched(url, fetch_time, size,
    187                                        true /* was_cached */,
    188                                        true /* is_connection_cellular */);
    189 }
    190 
    191 namespace {
    192 
    193 TEST_F(PrecacheDatabaseTest, PrecacheOverNetwork) {
    194   RecordPrecacheFromNetwork(kURL, kFetchTime, kSize);
    195 
    196   EXPECT_EQ(BuildURLTableMap(kURL, kFetchTime), GetActualURLTableMap());
    197 
    198   ExpectNewSample("Precache.DownloadedPrecacheMotivated", kSize);
    199   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    200   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    201   ExpectNoNewSamples("Precache.Saved");
    202   ExpectNoNewSamples("Precache.Saved.Cellular");
    203 }
    204 
    205 TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithURLTableEntry) {
    206   precache_url_table()->AddURL(kURL, kOldFetchTime);
    207   RecordPrecacheFromCache(kURL, kFetchTime, kSize);
    208 
    209   // The URL table entry should have been updated to have |kFetchTime| as the
    210   // timestamp.
    211   EXPECT_EQ(BuildURLTableMap(kURL, kFetchTime), GetActualURLTableMap());
    212 
    213   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    214   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    215   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    216   ExpectNoNewSamples("Precache.Saved");
    217   ExpectNoNewSamples("Precache.Saved.Cellular");
    218 }
    219 
    220 TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithoutURLTableEntry) {
    221   RecordPrecacheFromCache(kURL, kFetchTime, kSize);
    222 
    223   EXPECT_TRUE(GetActualURLTableMap().empty());
    224 
    225   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    226   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    227   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    228   ExpectNoNewSamples("Precache.Saved");
    229   ExpectNoNewSamples("Precache.Saved.Cellular");
    230 }
    231 
    232 TEST_F(PrecacheDatabaseTest, FetchOverNetwork_NonCellular) {
    233   RecordFetchFromNetwork(kURL, kFetchTime, kSize);
    234 
    235   EXPECT_TRUE(GetActualURLTableMap().empty());
    236 
    237   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    238   ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
    239   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    240   ExpectNoNewSamples("Precache.Saved");
    241   ExpectNoNewSamples("Precache.Saved.Cellular");
    242 }
    243 
    244 TEST_F(PrecacheDatabaseTest, FetchOverNetwork_Cellular) {
    245   RecordFetchFromNetworkCellular(kURL, kFetchTime, kSize);
    246 
    247   EXPECT_TRUE(GetActualURLTableMap().empty());
    248 
    249   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    250   ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
    251   ExpectNewSample("Precache.DownloadedNonPrecache.Cellular", kSize);
    252   ExpectNoNewSamples("Precache.Saved");
    253   ExpectNoNewSamples("Precache.Saved.Cellular");
    254 }
    255 
    256 TEST_F(PrecacheDatabaseTest, FetchOverNetworkWithURLTableEntry) {
    257   precache_url_table()->AddURL(kURL, kOldFetchTime);
    258   RecordFetchFromNetwork(kURL, kFetchTime, kSize);
    259 
    260   // The URL table entry should have been deleted.
    261   EXPECT_TRUE(GetActualURLTableMap().empty());
    262 
    263   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    264   ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
    265   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    266   ExpectNoNewSamples("Precache.Saved");
    267   ExpectNoNewSamples("Precache.Saved.Cellular");
    268 }
    269 
    270 TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_NonCellular) {
    271   precache_url_table()->AddURL(kURL, kOldFetchTime);
    272   RecordFetchFromCache(kURL, kFetchTime, kSize);
    273 
    274   // The URL table entry should have been deleted.
    275   EXPECT_TRUE(GetActualURLTableMap().empty());
    276 
    277   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    278   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    279   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    280   ExpectNewSample("Precache.Saved", kSize);
    281   ExpectNoNewSamples("Precache.Saved.Cellular");
    282 }
    283 
    284 TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_Cellular) {
    285   precache_url_table()->AddURL(kURL, kOldFetchTime);
    286   RecordFetchFromCacheCellular(kURL, kFetchTime, kSize);
    287 
    288   // The URL table entry should have been deleted.
    289   EXPECT_TRUE(GetActualURLTableMap().empty());
    290 
    291   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    292   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    293   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    294   ExpectNewSample("Precache.Saved", kSize);
    295   ExpectNewSample("Precache.Saved.Cellular", kSize);
    296 }
    297 
    298 TEST_F(PrecacheDatabaseTest, FetchFromCacheWithoutURLTableEntry) {
    299   RecordFetchFromCache(kURL, kFetchTime, kSize);
    300 
    301   EXPECT_TRUE(GetActualURLTableMap().empty());
    302 
    303   ExpectNoNewSamples("Precache.DownloadedPrecacheMotivated");
    304   ExpectNoNewSamples("Precache.DownloadedNonPrecache");
    305   ExpectNoNewSamples("Precache.DownloadedNonPrecache.Cellular");
    306   ExpectNoNewSamples("Precache.Saved");
    307   ExpectNoNewSamples("Precache.Saved.Cellular");
    308 }
    309 
    310 TEST_F(PrecacheDatabaseTest, DeleteExpiredPrecacheHistory) {
    311   const base::Time kToday = base::Time() + base::TimeDelta::FromDays(1000);
    312   const base::Time k59DaysAgo = kToday - base::TimeDelta::FromDays(59);
    313   const base::Time k61DaysAgo = kToday - base::TimeDelta::FromDays(61);
    314 
    315   precache_url_table()->AddURL(GURL("http://expired-precache.com"), k61DaysAgo);
    316   precache_url_table()->AddURL(GURL("http://old-precache.com"), k59DaysAgo);
    317 
    318   precache_database_->DeleteExpiredPrecacheHistory(kToday);
    319 
    320   EXPECT_EQ(BuildURLTableMap(GURL("http://old-precache.com"), k59DaysAgo),
    321             GetActualURLTableMap());
    322 }
    323 
    324 TEST_F(PrecacheDatabaseTest, SampleInteraction) {
    325   const GURL kURL1("http://url1.com");
    326   const int64 kSize1 = 1000;
    327   const GURL kURL2("http://url2.com");
    328   const int64 kSize2 = 2000;
    329   const GURL kURL3("http://url3.com");
    330   const int64 kSize3 = 3000;
    331   const GURL kURL4("http://url4.com");
    332   const int64 kSize4 = 4000;
    333   const GURL kURL5("http://url5.com");
    334   const int64 kSize5 = 5000;
    335 
    336   RecordPrecacheFromNetwork(kURL1, kFetchTime, kSize1);
    337   RecordPrecacheFromNetwork(kURL2, kFetchTime, kSize2);
    338   RecordPrecacheFromNetwork(kURL3, kFetchTime, kSize3);
    339   RecordPrecacheFromNetwork(kURL4, kFetchTime, kSize4);
    340 
    341   RecordFetchFromCacheCellular(kURL1, kFetchTime, kSize1);
    342   RecordFetchFromCacheCellular(kURL1, kFetchTime, kSize1);
    343   RecordFetchFromNetworkCellular(kURL2, kFetchTime, kSize2);
    344   RecordFetchFromNetworkCellular(kURL5, kFetchTime, kSize5);
    345   RecordFetchFromCacheCellular(kURL5, kFetchTime, kSize5);
    346 
    347   RecordPrecacheFromCache(kURL1, kFetchTime, kSize1);
    348   RecordPrecacheFromNetwork(kURL2, kFetchTime, kSize2);
    349   RecordPrecacheFromCache(kURL3, kFetchTime, kSize3);
    350   RecordPrecacheFromCache(kURL4, kFetchTime, kSize4);
    351 
    352   RecordFetchFromCache(kURL1, kFetchTime, kSize1);
    353   RecordFetchFromNetwork(kURL2, kFetchTime, kSize2);
    354   RecordFetchFromCache(kURL3, kFetchTime, kSize3);
    355   RecordFetchFromCache(kURL5, kFetchTime, kSize5);
    356 
    357   scoped_ptr<base::HistogramSamples> downloaded_precache_motivated_bytes(
    358       GetHistogramSamplesDelta("Precache.DownloadedPrecacheMotivated"));
    359   EXPECT_EQ(5, downloaded_precache_motivated_bytes->TotalCount());
    360   EXPECT_EQ(1, downloaded_precache_motivated_bytes->GetCount(kSize1));
    361   EXPECT_EQ(2, downloaded_precache_motivated_bytes->GetCount(kSize2));
    362   EXPECT_EQ(1, downloaded_precache_motivated_bytes->GetCount(kSize3));
    363   EXPECT_EQ(1, downloaded_precache_motivated_bytes->GetCount(kSize4));
    364 
    365   scoped_ptr<base::HistogramSamples> downloaded_non_precache_bytes(
    366       GetHistogramSamplesDelta("Precache.DownloadedNonPrecache"));
    367   EXPECT_EQ(3, downloaded_non_precache_bytes->TotalCount());
    368   EXPECT_EQ(2, downloaded_non_precache_bytes->GetCount(kSize2));
    369   EXPECT_EQ(1, downloaded_non_precache_bytes->GetCount(kSize5));
    370 
    371   scoped_ptr<base::HistogramSamples> downloaded_non_precache_bytes_cellular(
    372       GetHistogramSamplesDelta("Precache.DownloadedNonPrecache.Cellular"));
    373   EXPECT_EQ(2, downloaded_non_precache_bytes_cellular->TotalCount());
    374   EXPECT_EQ(1, downloaded_non_precache_bytes_cellular->GetCount(kSize2));
    375   EXPECT_EQ(1, downloaded_non_precache_bytes_cellular->GetCount(kSize5));
    376 
    377   scoped_ptr<base::HistogramSamples> saved_bytes(
    378       GetHistogramSamplesDelta("Precache.Saved"));
    379   EXPECT_EQ(2, saved_bytes->TotalCount());
    380   EXPECT_EQ(1, saved_bytes->GetCount(kSize1));
    381   EXPECT_EQ(1, saved_bytes->GetCount(kSize3));
    382 
    383   scoped_ptr<base::HistogramSamples> saved_bytes_cellular(
    384       GetHistogramSamplesDelta("Precache.Saved.Cellular"));
    385   EXPECT_EQ(1, saved_bytes_cellular->TotalCount());
    386   EXPECT_EQ(1, saved_bytes_cellular->GetCount(kSize1));
    387 }
    388 
    389 }  // namespace
    390 
    391 }  // namespace precache
    392