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