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/thread_task_runner_handle.h"
17 #include "components/precache/core/precache_switches.h"
18 #include "components/precache/core/proto/precache.pb.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_status_code.h"
21 #include "net/url_request/test_url_fetcher_factory.h"
22 #include "net/url_request/url_request_status.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
30 class TestURLFetcherCallback
{
32 scoped_ptr
<net::FakeURLFetcher
> CreateURLFetcher(
33 const GURL
& url
, net::URLFetcherDelegate
* delegate
,
34 const std::string
& response_data
, net::HttpStatusCode response_code
,
35 net::URLRequestStatus::Status status
) {
36 scoped_ptr
<net::FakeURLFetcher
> fetcher(new net::FakeURLFetcher(
37 url
, delegate
, response_data
, response_code
, status
));
39 if (response_code
== net::HTTP_OK
) {
40 scoped_refptr
<net::HttpResponseHeaders
> download_headers
=
41 new net::HttpResponseHeaders("");
42 download_headers
->AddHeader("Content-Type: text/html");
43 fetcher
->set_response_headers(download_headers
);
46 requested_urls_
.insert(url
);
47 return fetcher
.Pass();
50 const std::multiset
<GURL
>& requested_urls() const {
51 return requested_urls_
;
55 // Multiset with one entry for each URL requested.
56 std::multiset
<GURL
> requested_urls_
;
59 class TestPrecacheDelegate
: public PrecacheFetcher::PrecacheDelegate
{
61 TestPrecacheDelegate() : was_on_done_called_(false) {}
63 void OnDone() override
{ was_on_done_called_
= true; }
65 bool was_on_done_called() const {
66 return was_on_done_called_
;
70 bool was_on_done_called_
;
73 class PrecacheFetcherTest
: public testing::Test
{
76 : request_context_(new net::TestURLRequestContextGetter(
77 base::ThreadTaskRunnerHandle::Get())),
79 base::Bind(&TestURLFetcherCallback::CreateURLFetcher
,
80 base::Unretained(&url_callback_
))) {}
83 base::MessageLoopForUI loop_
;
84 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_
;
85 TestURLFetcherCallback url_callback_
;
86 net::FakeURLFetcherFactory factory_
;
87 TestPrecacheDelegate precache_delegate_
;
90 const char kConfigURL
[] = "http://config-url.com";
91 const char kManifestURLPrefix
[] = "http://manifest-url-prefix.com/";
92 const char kCustomManifestURLPrefix
[] =
93 "http://custom-manifest-url-prefix.com/";
94 const char kManifestFetchFailureURL
[] =
95 "http://manifest-url-prefix.com/manifest-fetch-failure.com";
96 const char kBadManifestURL
[] =
97 "http://manifest-url-prefix.com/bad-manifest.com";
98 const char kGoodManifestURL
[] =
99 "http://manifest-url-prefix.com/good-manifest.com";
100 const char kCustomGoodManifestURL
[] =
101 "http://custom-manifest-url-prefix.com/good-manifest.com";
102 const char kResourceFetchFailureURL
[] = "http://resource-fetch-failure.com";
103 const char kGoodResourceURL
[] = "http://good-resource.com";
104 const char kForcedStartingURLManifestURL
[] =
105 "http://manifest-url-prefix.com/forced-starting-url.com";
107 TEST_F(PrecacheFetcherTest
, FullPrecache
) {
108 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
109 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
110 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
111 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
113 std::vector
<std::string
> starting_hosts
;
114 starting_hosts
.push_back("manifest-fetch-failure.com");
115 starting_hosts
.push_back("bad-manifest.com");
116 starting_hosts
.push_back("good-manifest.com");
117 starting_hosts
.push_back("not-in-top-3.com");
119 PrecacheConfigurationSettings config
;
120 config
.set_top_sites_count(3);
121 config
.add_forced_site("forced-starting-url.com");
122 // Duplicate starting URL, the manifest for this should only be fetched once.
123 config
.add_forced_site("good-manifest.com");
125 PrecacheManifest good_manifest
;
126 good_manifest
.add_resource()->set_url(kResourceFetchFailureURL
);
127 good_manifest
.add_resource(); // Resource with no URL, should not be fetched.
128 good_manifest
.add_resource()->set_url(kGoodResourceURL
);
130 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
131 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
132 factory_
.SetFakeResponse(GURL(kManifestFetchFailureURL
), "",
133 net::HTTP_INTERNAL_SERVER_ERROR
,
134 net::URLRequestStatus::FAILED
);
135 factory_
.SetFakeResponse(GURL(kBadManifestURL
), "bad protobuf", net::HTTP_OK
,
136 net::URLRequestStatus::SUCCESS
);
137 factory_
.SetFakeResponse(GURL(kGoodManifestURL
),
138 good_manifest
.SerializeAsString(), net::HTTP_OK
,
139 net::URLRequestStatus::SUCCESS
);
140 factory_
.SetFakeResponse(GURL(kResourceFetchFailureURL
),
141 "", net::HTTP_INTERNAL_SERVER_ERROR
,
142 net::URLRequestStatus::FAILED
);
143 factory_
.SetFakeResponse(GURL(kGoodResourceURL
), "good", net::HTTP_OK
,
144 net::URLRequestStatus::SUCCESS
);
145 factory_
.SetFakeResponse(GURL(kForcedStartingURLManifestURL
),
146 PrecacheManifest().SerializeAsString(), net::HTTP_OK
,
147 net::URLRequestStatus::SUCCESS
);
149 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
150 std::string(), &precache_delegate_
);
151 precache_fetcher
.Start();
153 base::MessageLoop::current()->RunUntilIdle();
155 std::multiset
<GURL
> expected_requested_urls
;
156 expected_requested_urls
.insert(GURL(kConfigURL
));
157 expected_requested_urls
.insert(GURL(kManifestFetchFailureURL
));
158 expected_requested_urls
.insert(GURL(kBadManifestURL
));
159 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
160 expected_requested_urls
.insert(GURL(kResourceFetchFailureURL
));
161 expected_requested_urls
.insert(GURL(kGoodResourceURL
));
162 expected_requested_urls
.insert(GURL(kForcedStartingURLManifestURL
));
164 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
166 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
169 TEST_F(PrecacheFetcherTest
, CustomManifestURLPrefix
) {
170 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
171 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
172 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
173 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
175 std::vector
<std::string
> starting_hosts
;
176 starting_hosts
.push_back("good-manifest.com");
178 PrecacheConfigurationSettings config
;
180 PrecacheManifest good_manifest
;
181 good_manifest
.add_resource()->set_url(kGoodResourceURL
);
183 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
184 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
185 factory_
.SetFakeResponse(GURL(kCustomGoodManifestURL
),
186 good_manifest
.SerializeAsString(), net::HTTP_OK
,
187 net::URLRequestStatus::SUCCESS
);
188 factory_
.SetFakeResponse(GURL(kGoodResourceURL
), "good", net::HTTP_OK
,
189 net::URLRequestStatus::SUCCESS
);
191 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
192 kCustomManifestURLPrefix
,
193 &precache_delegate_
);
194 precache_fetcher
.Start();
196 base::MessageLoop::current()->RunUntilIdle();
198 std::multiset
<GURL
> expected_requested_urls
;
199 expected_requested_urls
.insert(GURL(kConfigURL
));
200 expected_requested_urls
.insert(GURL(kCustomGoodManifestURL
));
201 expected_requested_urls
.insert(GURL(kGoodResourceURL
));
203 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
205 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
208 TEST_F(PrecacheFetcherTest
, ConfigFetchFailure
) {
209 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
210 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
211 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
212 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
214 std::vector
<std::string
> starting_hosts(1, "good-manifest.com");
216 factory_
.SetFakeResponse(GURL(kConfigURL
), "",
217 net::HTTP_INTERNAL_SERVER_ERROR
,
218 net::URLRequestStatus::FAILED
);
219 factory_
.SetFakeResponse(GURL(kGoodManifestURL
), "", net::HTTP_OK
,
220 net::URLRequestStatus::SUCCESS
);
222 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
223 std::string(), &precache_delegate_
);
224 precache_fetcher
.Start();
226 base::MessageLoop::current()->RunUntilIdle();
228 std::multiset
<GURL
> expected_requested_urls
;
229 expected_requested_urls
.insert(GURL(kConfigURL
));
230 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
231 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
233 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
236 TEST_F(PrecacheFetcherTest
, BadConfig
) {
237 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
238 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
239 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
240 switches::kPrecacheManifestURLPrefix
, kManifestURLPrefix
);
242 std::vector
<std::string
> starting_hosts(1, "good-manifest.com");
244 factory_
.SetFakeResponse(GURL(kConfigURL
), "bad protobuf", net::HTTP_OK
,
245 net::URLRequestStatus::SUCCESS
);
246 factory_
.SetFakeResponse(GURL(kGoodManifestURL
), "", net::HTTP_OK
,
247 net::URLRequestStatus::SUCCESS
);
249 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
250 std::string(), &precache_delegate_
);
251 precache_fetcher
.Start();
253 base::MessageLoop::current()->RunUntilIdle();
255 std::multiset
<GURL
> expected_requested_urls
;
256 expected_requested_urls
.insert(GURL(kConfigURL
));
257 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
258 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
260 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
263 TEST_F(PrecacheFetcherTest
, Cancel
) {
264 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
265 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
267 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
269 PrecacheConfigurationSettings config
;
270 config
.set_top_sites_count(1);
272 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
273 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
275 scoped_ptr
<PrecacheFetcher
> precache_fetcher(
276 new PrecacheFetcher(starting_hosts
, request_context_
.get(), std::string(),
277 &precache_delegate_
));
278 precache_fetcher
->Start();
280 // Destroy the PrecacheFetcher to cancel precaching. This should not cause
281 // OnDone to be called on the precache delegate.
282 precache_fetcher
.reset();
284 base::MessageLoop::current()->RunUntilIdle();
286 std::multiset
<GURL
> expected_requested_urls
;
287 expected_requested_urls
.insert(GURL(kConfigURL
));
288 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
290 EXPECT_FALSE(precache_delegate_
.was_on_done_called());
293 #if defined(PRECACHE_CONFIG_SETTINGS_URL)
295 // If the default precache configuration settings URL is defined, then test that
296 // it works with the PrecacheFetcher.
297 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultConfigSettingsURL
) {
298 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
300 PrecacheConfigurationSettings config
;
301 config
.set_top_sites_count(0);
303 factory_
.SetFakeResponse(GURL(PRECACHE_CONFIG_SETTINGS_URL
),
304 config
.SerializeAsString(), net::HTTP_OK
,
305 net::URLRequestStatus::SUCCESS
);
307 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
308 std::string(), &precache_delegate_
);
309 precache_fetcher
.Start();
311 base::MessageLoop::current()->RunUntilIdle();
313 std::multiset
<GURL
> expected_requested_urls
;
314 expected_requested_urls
.insert(GURL(PRECACHE_CONFIG_SETTINGS_URL
));
315 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
317 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
320 #endif // PRECACHE_CONFIG_SETTINGS_URL
322 #if defined(PRECACHE_MANIFEST_URL_PREFIX)
324 // If the default precache manifest URL prefix is defined, then test that it
325 // works with the PrecacheFetcher.
326 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultManifestURLPrefix
) {
327 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
328 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
330 std::vector
<std::string
> starting_hosts(1, "starting-url.com");
332 PrecacheConfigurationSettings config
;
333 config
.set_top_sites_count(1);
335 GURL
manifest_url(PRECACHE_MANIFEST_URL_PREFIX
"starting-url.com");
337 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
338 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
339 factory_
.SetFakeResponse(manifest_url
, PrecacheManifest().SerializeAsString(),
340 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
342 PrecacheFetcher
precache_fetcher(starting_hosts
, request_context_
.get(),
343 std::string(), &precache_delegate_
);
344 precache_fetcher
.Start();
346 base::MessageLoop::current()->RunUntilIdle();
348 std::multiset
<GURL
> expected_requested_urls
;
349 expected_requested_urls
.insert(GURL(kConfigURL
));
350 expected_requested_urls
.insert(manifest_url
);
351 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
353 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
356 #endif // PRECACHE_MANIFEST_URL_PREFIX
360 } // namespace precache