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_fetcher.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/test/histogram_tester.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "components/precache/core/precache_switches.h"
19 #include "components/precache/core/proto/precache.pb.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_status_code.h"
22 #include "net/url_request/test_url_fetcher_factory.h"
23 #include "net/url_request/url_request_status.h"
24 #include "net/url_request/url_request_test_util.h"
25 #include "testing/gtest/include/gtest/gtest.h"
31 class TestURLFetcherCallback
{
33 TestURLFetcherCallback() : total_response_bytes_(0) {}
35 scoped_ptr
<net::FakeURLFetcher
> CreateURLFetcher(
36 const GURL
& url
, net::URLFetcherDelegate
* delegate
,
37 const std::string
& response_data
, net::HttpStatusCode response_code
,
38 net::URLRequestStatus::Status status
) {
39 scoped_ptr
<net::FakeURLFetcher
> fetcher(new net::FakeURLFetcher(
40 url
, delegate
, response_data
, response_code
, status
));
42 if (response_code
== net::HTTP_OK
) {
43 scoped_refptr
<net::HttpResponseHeaders
> download_headers
=
44 new net::HttpResponseHeaders("");
45 download_headers
->AddHeader("Content-Type: text/html");
46 fetcher
->set_response_headers(download_headers
);
49 total_response_bytes_
+= response_data
.size();
50 requested_urls_
.insert(url
);
51 return fetcher
.Pass();
54 const std::multiset
<GURL
>& requested_urls() const {
55 return requested_urls_
;
58 int total_response_bytes() const { return total_response_bytes_
; }
61 // Multiset with one entry for each URL requested.
62 std::multiset
<GURL
> requested_urls_
;
63 int total_response_bytes_
;
66 class TestPrecacheDelegate
: public PrecacheFetcher::PrecacheDelegate
{
68 TestPrecacheDelegate() : was_on_done_called_(false) {}
70 void OnDone() override
{ was_on_done_called_
= true; }
72 bool was_on_done_called() const {
73 return was_on_done_called_
;
77 bool was_on_done_called_
;
80 class PrecacheFetcherTest
: public testing::Test
{
83 : request_context_(new net::TestURLRequestContextGetter(
84 base::ThreadTaskRunnerHandle::Get())),
86 base::Bind(&TestURLFetcherCallback::CreateURLFetcher
,
87 base::Unretained(&url_callback_
))),
88 expected_total_response_bytes_(0) {}
91 base::MessageLoopForUI loop_
;
92 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_
;
93 TestURLFetcherCallback url_callback_
;
94 net::FakeURLFetcherFactory factory_
;
95 TestPrecacheDelegate precache_delegate_
;
96 int expected_total_response_bytes_
;
99 const char kConfigURL
[] = "http://config-url.com";
100 const char kManifestURLPrefix
[] = "http://manifest-url-prefix.com/";
101 const char kCustomManifestURLPrefix
[] =
102 "http://custom-manifest-url-prefix.com/";
103 const char kManifestFetchFailureURL
[] =
104 "http://manifest-url-prefix.com/manifest-fetch-failure.com";
105 const char kBadManifestURL
[] =
106 "http://manifest-url-prefix.com/bad-manifest.com";
107 const char kGoodManifestURL
[] =
108 "http://manifest-url-prefix.com/good-manifest.com";
109 const char kCustomGoodManifestURL
[] =
110 "http://custom-manifest-url-prefix.com/good-manifest.com";
111 const char kResourceFetchFailureURL
[] = "http://resource-fetch-failure.com";
112 const char kGoodResourceURL
[] = "http://good-resource.com";
113 const char kForcedStartingURLManifestURL
[] =
114 "http://manifest-url-prefix.com/forced-starting-url.com";
116 TEST_F(PrecacheFetcherTest
, FullPrecache
) {
117 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
118 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
119 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
120 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
122 std::vector
<std::string
> starting_hosts
;
123 starting_hosts
.push_back("manifest-fetch-failure.com");
124 starting_hosts
.push_back("bad-manifest.com");
125 starting_hosts
.push_back("good-manifest.com");
126 starting_hosts
.push_back("not-in-top-3.com");
128 PrecacheConfigurationSettings config
;
129 config
.set_top_sites_count(3);
130 config
.add_forced_site("forced-starting-url.com");
131 // Duplicate starting URL, the manifest for this should only be fetched once.
132 config
.add_forced_site("good-manifest.com");
134 PrecacheManifest good_manifest
;
135 good_manifest
.add_resource()->set_url(kResourceFetchFailureURL
);
136 good_manifest
.add_resource(); // Resource with no URL, should not be fetched.
137 good_manifest
.add_resource()->set_url(kGoodResourceURL
);
139 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
140 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
141 factory_
.SetFakeResponse(GURL(kManifestFetchFailureURL
), "",
142 net::HTTP_INTERNAL_SERVER_ERROR
,
143 net::URLRequestStatus::FAILED
);
144 factory_
.SetFakeResponse(GURL(kBadManifestURL
), "bad protobuf", net::HTTP_OK
,
145 net::URLRequestStatus::SUCCESS
);
146 factory_
.SetFakeResponse(GURL(kGoodManifestURL
),
147 good_manifest
.SerializeAsString(), net::HTTP_OK
,
148 net::URLRequestStatus::SUCCESS
);
149 factory_
.SetFakeResponse(GURL(kResourceFetchFailureURL
),
150 "", net::HTTP_INTERNAL_SERVER_ERROR
,
151 net::URLRequestStatus::FAILED
);
152 factory_
.SetFakeResponse(GURL(kGoodResourceURL
), "good", net::HTTP_OK
,
153 net::URLRequestStatus::SUCCESS
);
154 factory_
.SetFakeResponse(GURL(kForcedStartingURLManifestURL
),
155 PrecacheManifest().SerializeAsString(), net::HTTP_OK
,
156 net::URLRequestStatus::SUCCESS
);
158 base::HistogramTester histogram
;
161 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
162 std::string(), &precache_delegate_
);
163 precache_fetcher
.Start();
165 base::MessageLoop::current()->RunUntilIdle();
167 // Destroy the PrecacheFetcher after it has finished, to record metrics.
170 std::multiset
<GURL
> expected_requested_urls
;
171 expected_requested_urls
.insert(GURL(kConfigURL
));
172 expected_requested_urls
.insert(GURL(kManifestFetchFailureURL
));
173 expected_requested_urls
.insert(GURL(kBadManifestURL
));
174 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
175 expected_requested_urls
.insert(GURL(kResourceFetchFailureURL
));
176 expected_requested_urls
.insert(GURL(kGoodResourceURL
));
177 expected_requested_urls
.insert(GURL(kForcedStartingURLManifestURL
));
179 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
181 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
183 histogram
.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
184 histogram
.ExpectUniqueSample("Precache.Fetch.ResponseBytes",
185 url_callback_
.total_response_bytes(), 1);
188 TEST_F(PrecacheFetcherTest
, CustomManifestURLPrefix
) {
189 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
190 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
191 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
192 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
194 std::vector
<std::string
> starting_hosts
;
195 starting_hosts
.push_back("good-manifest.com");
197 PrecacheConfigurationSettings config
;
199 PrecacheManifest good_manifest
;
200 good_manifest
.add_resource()->set_url(kGoodResourceURL
);
202 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
203 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
204 factory_
.SetFakeResponse(GURL(kCustomGoodManifestURL
),
205 good_manifest
.SerializeAsString(), net::HTTP_OK
,
206 net::URLRequestStatus::SUCCESS
);
207 factory_
.SetFakeResponse(GURL(kGoodResourceURL
), "good", net::HTTP_OK
,
208 net::URLRequestStatus::SUCCESS
);
210 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
211 kCustomManifestURLPrefix
,
212 &precache_delegate_
);
213 precache_fetcher
.Start();
215 base::MessageLoop::current()->RunUntilIdle();
217 std::multiset
<GURL
> expected_requested_urls
;
218 expected_requested_urls
.insert(GURL(kConfigURL
));
219 expected_requested_urls
.insert(GURL(kCustomGoodManifestURL
));
220 expected_requested_urls
.insert(GURL(kGoodResourceURL
));
222 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
224 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
227 TEST_F(PrecacheFetcherTest
, ConfigFetchFailure
) {
228 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
229 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
230 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
231 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
233 std::vector
<std::string
> starting_hosts(1, "good-manifest.com");
235 factory_
.SetFakeResponse(GURL(kConfigURL
), "",
236 net::HTTP_INTERNAL_SERVER_ERROR
,
237 net::URLRequestStatus::FAILED
);
238 factory_
.SetFakeResponse(GURL(kGoodManifestURL
), "", net::HTTP_OK
,
239 net::URLRequestStatus::SUCCESS
);
241 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
242 std::string(), &precache_delegate_
);
243 precache_fetcher
.Start();
245 base::MessageLoop::current()->RunUntilIdle();
247 std::multiset
<GURL
> expected_requested_urls
;
248 expected_requested_urls
.insert(GURL(kConfigURL
));
249 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
250 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
252 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
255 TEST_F(PrecacheFetcherTest
, BadConfig
) {
256 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
257 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
258 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
259 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
261 std::vector
<std::string
> starting_hosts(1, "good-manifest.com");
263 factory_
.SetFakeResponse(GURL(kConfigURL
), "bad protobuf", net::HTTP_OK
,
264 net::URLRequestStatus::SUCCESS
);
265 factory_
.SetFakeResponse(GURL(kGoodManifestURL
), "", net::HTTP_OK
,
266 net::URLRequestStatus::SUCCESS
);
268 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
269 std::string(), &precache_delegate_
);
270 precache_fetcher
.Start();
272 base::MessageLoop::current()->RunUntilIdle();
274 std::multiset
<GURL
> expected_requested_urls
;
275 expected_requested_urls
.insert(GURL(kConfigURL
));
276 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
277 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
279 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
282 TEST_F(PrecacheFetcherTest
, Cancel
) {
283 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
284 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
286 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
288 PrecacheConfigurationSettings config
;
289 config
.set_top_sites_count(1);
291 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
292 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
294 base::HistogramTester histogram
;
297 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
298 std::string(), &precache_delegate_
);
299 precache_fetcher
.Start();
301 // Destroy the PrecacheFetcher, to cancel precaching and record metrics.
302 // This should not cause OnDone to be called on the precache delegate.
305 base::MessageLoop::current()->RunUntilIdle();
307 std::multiset
<GURL
> expected_requested_urls
;
308 expected_requested_urls
.insert(GURL(kConfigURL
));
309 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
311 EXPECT_FALSE(precache_delegate_
.was_on_done_called());
313 histogram
.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 0, 1);
314 histogram
.ExpectUniqueSample("Precache.Fetch.ResponseBytes", 0, 1);
317 #if defined(PRECACHE_CONFIG_SETTINGS_URL)
319 // If the default precache configuration settings URL is defined, then test that
320 // it works with the PrecacheFetcher.
321 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultConfigSettingsURL
) {
322 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
324 PrecacheConfigurationSettings config
;
325 config
.set_top_sites_count(0);
327 factory_
.SetFakeResponse(GURL(PRECACHE_CONFIG_SETTINGS_URL
),
328 config
.SerializeAsString(), net::HTTP_OK
,
329 net::URLRequestStatus::SUCCESS
);
331 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
332 std::string(), &precache_delegate_
);
333 precache_fetcher
.Start();
335 base::MessageLoop::current()->RunUntilIdle();
337 std::multiset
<GURL
> expected_requested_urls
;
338 expected_requested_urls
.insert(GURL(PRECACHE_CONFIG_SETTINGS_URL
));
339 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
341 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
344 #endif // PRECACHE_CONFIG_SETTINGS_URL
346 #if defined(PRECACHE_MANIFEST_URL_PREFIX)
348 // If the default precache manifest URL prefix is defined, then test that it
349 // works with the PrecacheFetcher.
350 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultManifestURLPrefix
) {
351 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
352 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
354 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
356 PrecacheConfigurationSettings config
;
357 config
.set_top_sites_count(1);
359 GURL
manifest_url(PRECACHE_MANIFEST_URL_PREFIX
"starting-url.com");
361 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
362 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
363 factory_
.SetFakeResponse(manifest_url
, PrecacheManifest().SerializeAsString(),
364 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
366 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
367 std::string(), &precache_delegate_
);
368 precache_fetcher
.Start();
370 base::MessageLoop::current()->RunUntilIdle();
372 std::multiset
<GURL
> expected_requested_urls
;
373 expected_requested_urls
.insert(GURL(kConfigURL
));
374 expected_requested_urls
.insert(manifest_url
);
375 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
377 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
380 #endif // PRECACHE_MANIFEST_URL_PREFIX
384 } // namespace precache