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.
5 #include "components/precache/core/precache_database.h"
9 #include "base/containers/hash_tables.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram_base.h"
14 #include "base/test/histogram_tester.h"
15 #include "base/time/time.h"
16 #include "components/history/core/browser/history_constants.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
23 using ::testing::ContainerEq
;
24 using ::testing::ElementsAre
;
27 const GURL
kURL("http://url.com");
28 const base::TimeDelta kLatency
= base::TimeDelta::FromMilliseconds(5);
29 const base::Time kFetchTime
= base::Time() + base::TimeDelta::FromHours(1000);
30 const base::Time kOldFetchTime
= kFetchTime
- base::TimeDelta::FromDays(1);
31 const int64 kSize
= 5000;
33 std::map
<GURL
, base::Time
> BuildURLTableMap(const GURL
& url
,
34 const base::Time
& precache_time
) {
35 std::map
<GURL
, base::Time
> url_table_map
;
36 url_table_map
[url
] = precache_time
;
44 class PrecacheDatabaseTest
: public testing::Test
{
46 PrecacheDatabaseTest() {}
47 ~PrecacheDatabaseTest() override
{}
50 void SetUp() override
{
51 precache_database_
= new PrecacheDatabase();
53 ASSERT_TRUE(scoped_temp_dir_
.CreateUniqueTempDir());
54 base::FilePath db_path
= scoped_temp_dir_
.path().Append(
55 base::FilePath(FILE_PATH_LITERAL("precache_database")));
56 precache_database_
->Init(db_path
);
59 std::map
<GURL
, base::Time
> GetActualURLTableMap() {
60 // Flush any buffered writes so that the URL table will be up to date.
61 precache_database_
->Flush();
63 std::map
<GURL
, base::Time
> url_table_map
;
64 precache_url_table()->GetAllDataForTesting(&url_table_map
);
68 PrecacheURLTable
* precache_url_table() {
69 return &precache_database_
->precache_url_table_
;
72 // Convenience methods for recording different types of URL fetches. These
73 // exist to improve the readability of the tests.
74 void RecordPrecacheFromNetwork(const GURL
& url
,
75 base::TimeDelta latency
,
76 const base::Time
& fetch_time
,
78 void RecordPrecacheFromCache(const GURL
& url
, const base::Time
& fetch_time
,
80 void RecordFetchFromNetwork(const GURL
& url
,
81 base::TimeDelta latency
,
82 const base::Time
& fetch_time
,
84 void RecordFetchFromNetwork(const GURL
& url
,
85 base::TimeDelta latency
,
86 const base::Time
& fetch_time
,
89 void RecordFetchFromNetworkCellular(const GURL
& url
,
90 base::TimeDelta latency
,
91 const base::Time
& fetch_time
,
93 void RecordFetchFromCache(const GURL
& url
, const base::Time
& fetch_time
,
95 void RecordFetchFromCacheCellular(const GURL
& url
,
96 const base::Time
& fetch_time
, int64 size
);
98 // Having this MessageLoop member variable causes base::MessageLoop::current()
99 // to be set properly.
100 base::MessageLoopForUI loop_
;
102 scoped_refptr
<PrecacheDatabase
> precache_database_
;
103 base::ScopedTempDir scoped_temp_dir_
;
104 base::HistogramTester histograms_
;
105 base::HistogramTester::CountsMap expected_histogram_counts_
;
107 void ExpectNewSample(const std::string
& histogram_name
,
108 base::HistogramBase::Sample sample
) {
109 histograms_
.ExpectUniqueSample(histogram_name
, sample
, 1);
110 expected_histogram_counts_
[histogram_name
]++;
113 void ExpectNoOtherSamples() {
114 EXPECT_THAT(histograms_
.GetTotalCountsForPrefix("Precache."),
115 ContainerEq(expected_histogram_counts_
));
119 void PrecacheDatabaseTest::RecordPrecacheFromNetwork(
121 base::TimeDelta latency
,
122 const base::Time
& fetch_time
,
124 precache_database_
->RecordURLPrefetch(url
, latency
, fetch_time
, size
,
125 false /* was_cached */);
128 void PrecacheDatabaseTest::RecordPrecacheFromCache(const GURL
& url
,
129 const base::Time
& fetch_time
,
131 precache_database_
->RecordURLPrefetch(url
, base::TimeDelta() /* latency */,
133 true /* was_cached */);
136 void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL
& url
,
137 base::TimeDelta latency
,
138 const base::Time
& fetch_time
,
140 precache_database_
->RecordURLNonPrefetch(
141 url
, latency
, fetch_time
, size
, false /* was_cached */,
142 history::kMaxTopHosts
, false /* is_connection_cellular */);
145 void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL
& url
,
146 base::TimeDelta latency
,
147 const base::Time
& fetch_time
,
150 precache_database_
->RecordURLNonPrefetch(url
, latency
, fetch_time
, size
,
151 false /* was_cached */, host_rank
,
152 false /* is_connection_cellular */);
155 void PrecacheDatabaseTest::RecordFetchFromNetworkCellular(
157 base::TimeDelta latency
,
158 const base::Time
& fetch_time
,
160 precache_database_
->RecordURLNonPrefetch(
161 url
, latency
, fetch_time
, size
, false /* was_cached */,
162 history::kMaxTopHosts
, true /* is_connection_cellular */);
165 void PrecacheDatabaseTest::RecordFetchFromCache(const GURL
& url
,
166 const base::Time
& fetch_time
,
168 precache_database_
->RecordURLNonPrefetch(
169 url
, base::TimeDelta() /* latency */, fetch_time
, size
,
170 true /* was_cached */, history::kMaxTopHosts
,
171 false /* is_connection_cellular */);
174 void PrecacheDatabaseTest::RecordFetchFromCacheCellular(
175 const GURL
& url
, const base::Time
& fetch_time
, int64 size
) {
176 precache_database_
->RecordURLNonPrefetch(
177 url
, base::TimeDelta() /* latency */, fetch_time
, size
,
178 true /* was_cached */, history::kMaxTopHosts
,
179 true /* is_connection_cellular */);
184 TEST_F(PrecacheDatabaseTest
, PrecacheOverNetwork
) {
185 RecordPrecacheFromNetwork(kURL
, kLatency
, kFetchTime
, kSize
);
187 EXPECT_EQ(BuildURLTableMap(kURL
, kFetchTime
), GetActualURLTableMap());
189 ExpectNewSample("Precache.DownloadedPrecacheMotivated", kSize
);
190 ExpectNewSample("Precache.Latency.Prefetch", kLatency
.InMilliseconds());
191 ExpectNoOtherSamples();
194 TEST_F(PrecacheDatabaseTest
, PrecacheFromCacheWithURLTableEntry
) {
195 precache_url_table()->AddURL(kURL
, kOldFetchTime
);
196 RecordPrecacheFromCache(kURL
, kFetchTime
, kSize
);
198 // The URL table entry should have been updated to have |kFetchTime| as the
200 EXPECT_EQ(BuildURLTableMap(kURL
, kFetchTime
), GetActualURLTableMap());
202 ExpectNewSample("Precache.Latency.Prefetch", 0);
203 ExpectNoOtherSamples();
206 TEST_F(PrecacheDatabaseTest
, PrecacheFromCacheWithoutURLTableEntry
) {
207 RecordPrecacheFromCache(kURL
, kFetchTime
, kSize
);
209 EXPECT_TRUE(GetActualURLTableMap().empty());
211 ExpectNewSample("Precache.Latency.Prefetch", 0);
212 ExpectNoOtherSamples();
215 TEST_F(PrecacheDatabaseTest
, FetchOverNetwork_NonCellular
) {
216 RecordFetchFromNetwork(kURL
, kLatency
, kFetchTime
, kSize
);
218 EXPECT_TRUE(GetActualURLTableMap().empty());
220 ExpectNewSample("Precache.DownloadedNonPrecache", kSize
);
221 ExpectNewSample("Precache.Latency.NonPrefetch", kLatency
.InMilliseconds());
222 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
223 kLatency
.InMilliseconds());
224 ExpectNoOtherSamples();
227 TEST_F(PrecacheDatabaseTest
, FetchOverNetwork_NonCellular_TopHosts
) {
228 RecordFetchFromNetwork(kURL
, kLatency
, kFetchTime
, kSize
, 0 /* host_rank */);
230 EXPECT_TRUE(GetActualURLTableMap().empty());
232 ExpectNewSample("Precache.DownloadedNonPrecache", kSize
);
233 ExpectNewSample("Precache.Latency.NonPrefetch", kLatency
.InMilliseconds());
234 ExpectNewSample("Precache.Latency.NonPrefetch.TopHosts",
235 kLatency
.InMilliseconds());
236 ExpectNoOtherSamples();
239 TEST_F(PrecacheDatabaseTest
, FetchOverNetwork_Cellular
) {
240 RecordFetchFromNetworkCellular(kURL
, kLatency
, kFetchTime
, kSize
);
242 EXPECT_TRUE(GetActualURLTableMap().empty());
244 ExpectNewSample("Precache.DownloadedNonPrecache", kSize
);
245 ExpectNewSample("Precache.DownloadedNonPrecache.Cellular", kSize
);
246 ExpectNewSample("Precache.Latency.NonPrefetch", kLatency
.InMilliseconds());
247 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
248 kLatency
.InMilliseconds());
249 ExpectNoOtherSamples();
252 TEST_F(PrecacheDatabaseTest
, FetchOverNetworkWithURLTableEntry
) {
253 precache_url_table()->AddURL(kURL
, kOldFetchTime
);
254 RecordFetchFromNetwork(kURL
, kLatency
, kFetchTime
, kSize
);
256 // The URL table entry should have been deleted.
257 EXPECT_TRUE(GetActualURLTableMap().empty());
259 ExpectNewSample("Precache.DownloadedNonPrecache", kSize
);
260 ExpectNewSample("Precache.Latency.NonPrefetch", kLatency
.InMilliseconds());
261 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
262 kLatency
.InMilliseconds());
263 ExpectNoOtherSamples();
266 TEST_F(PrecacheDatabaseTest
, FetchFromCacheWithURLTableEntry_NonCellular
) {
267 precache_url_table()->AddURL(kURL
, kOldFetchTime
);
268 RecordFetchFromCache(kURL
, kFetchTime
, kSize
);
270 // The URL table entry should have been deleted.
271 EXPECT_TRUE(GetActualURLTableMap().empty());
273 ExpectNewSample("Precache.Latency.NonPrefetch", 0);
274 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
275 ExpectNewSample("Precache.Saved", kSize
);
276 ExpectNoOtherSamples();
279 TEST_F(PrecacheDatabaseTest
, FetchFromCacheWithURLTableEntry_Cellular
) {
280 precache_url_table()->AddURL(kURL
, kOldFetchTime
);
281 RecordFetchFromCacheCellular(kURL
, kFetchTime
, kSize
);
283 // The URL table entry should have been deleted.
284 EXPECT_TRUE(GetActualURLTableMap().empty());
286 ExpectNewSample("Precache.Latency.NonPrefetch", 0);
287 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
288 ExpectNewSample("Precache.Saved", kSize
);
289 ExpectNewSample("Precache.Saved.Cellular", kSize
);
290 ExpectNoOtherSamples();
293 TEST_F(PrecacheDatabaseTest
, FetchFromCacheWithoutURLTableEntry
) {
294 RecordFetchFromCache(kURL
, kFetchTime
, kSize
);
296 EXPECT_TRUE(GetActualURLTableMap().empty());
298 ExpectNewSample("Precache.Latency.NonPrefetch", 0);
299 ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
300 ExpectNoOtherSamples();
303 TEST_F(PrecacheDatabaseTest
, DeleteExpiredPrecacheHistory
) {
304 const base::Time kToday
= base::Time() + base::TimeDelta::FromDays(1000);
305 const base::Time k59DaysAgo
= kToday
- base::TimeDelta::FromDays(59);
306 const base::Time k61DaysAgo
= kToday
- base::TimeDelta::FromDays(61);
308 precache_url_table()->AddURL(GURL("http://expired-precache.com"), k61DaysAgo
);
309 precache_url_table()->AddURL(GURL("http://old-precache.com"), k59DaysAgo
);
311 precache_database_
->DeleteExpiredPrecacheHistory(kToday
);
313 EXPECT_EQ(BuildURLTableMap(GURL("http://old-precache.com"), k59DaysAgo
),
314 GetActualURLTableMap());
317 TEST_F(PrecacheDatabaseTest
, SampleInteraction
) {
318 const GURL
kURL1("http://url1.com");
319 const int64 kSize1
= 1;
320 const GURL
kURL2("http://url2.com");
321 const int64 kSize2
= 2;
322 const GURL
kURL3("http://url3.com");
323 const int64 kSize3
= 3;
324 const GURL
kURL4("http://url4.com");
325 const int64 kSize4
= 4;
326 const GURL
kURL5("http://url5.com");
327 const int64 kSize5
= 5;
329 RecordPrecacheFromNetwork(kURL1
, kLatency
, kFetchTime
, kSize1
);
330 RecordPrecacheFromNetwork(kURL2
, kLatency
, kFetchTime
, kSize2
);
331 RecordPrecacheFromNetwork(kURL3
, kLatency
, kFetchTime
, kSize3
);
332 RecordPrecacheFromNetwork(kURL4
, kLatency
, kFetchTime
, kSize4
);
334 RecordFetchFromCacheCellular(kURL1
, kFetchTime
, kSize1
);
335 RecordFetchFromCacheCellular(kURL1
, kFetchTime
, kSize1
);
336 RecordFetchFromNetworkCellular(kURL2
, kLatency
, kFetchTime
, kSize2
);
337 RecordFetchFromNetworkCellular(kURL5
, kLatency
, kFetchTime
, kSize5
);
338 RecordFetchFromCacheCellular(kURL5
, kFetchTime
, kSize5
);
340 RecordPrecacheFromCache(kURL1
, kFetchTime
, kSize1
);
341 RecordPrecacheFromNetwork(kURL2
, kLatency
, kFetchTime
, kSize2
);
342 RecordPrecacheFromCache(kURL3
, kFetchTime
, kSize3
);
343 RecordPrecacheFromCache(kURL4
, kFetchTime
, kSize4
);
345 RecordFetchFromCache(kURL1
, kFetchTime
, kSize1
);
346 RecordFetchFromNetwork(kURL2
, kLatency
, kFetchTime
, kSize2
);
347 RecordFetchFromCache(kURL3
, kFetchTime
, kSize3
);
348 RecordFetchFromCache(kURL5
, kFetchTime
, kSize5
);
350 EXPECT_THAT(histograms_
.GetAllSamples("Precache.DownloadedPrecacheMotivated"),
351 ElementsAre(Bucket(kSize1
, 1), Bucket(kSize2
, 2),
352 Bucket(kSize3
, 1), Bucket(kSize4
, 1)));
354 EXPECT_THAT(histograms_
.GetAllSamples("Precache.DownloadedNonPrecache"),
355 ElementsAre(Bucket(kSize2
, 2), Bucket(kSize5
, 1)));
358 histograms_
.GetAllSamples("Precache.DownloadedNonPrecache.Cellular"),
359 ElementsAre(Bucket(kSize2
, 1), Bucket(kSize5
, 1)));
361 EXPECT_THAT(histograms_
.GetAllSamples("Precache.Latency.Prefetch"),
362 ElementsAre(Bucket(0, 3), Bucket(kLatency
.InMilliseconds(), 5)));
364 EXPECT_THAT(histograms_
.GetAllSamples("Precache.Latency.NonPrefetch"),
365 ElementsAre(Bucket(0, 6), Bucket(kLatency
.InMilliseconds(), 3)));
367 EXPECT_THAT(histograms_
.GetAllSamples("Precache.Saved"),
368 ElementsAre(Bucket(kSize1
, 1), Bucket(kSize3
, 1)));
370 EXPECT_THAT(histograms_
.GetAllSamples("Precache.Saved.Cellular"),
371 ElementsAre(Bucket(kSize1
, 1)));
376 } // namespace precache