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/message_loop/message_loop.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::MessageLoopProxy::current())),
78 factory_(NULL
, base::Bind(&TestURLFetcherCallback::CreateURLFetcher
,
79 base::Unretained(&url_callback_
))) {}
82 base::MessageLoopForUI loop_
;
83 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_
;
84 TestURLFetcherCallback url_callback_
;
85 net::FakeURLFetcherFactory factory_
;
86 TestPrecacheDelegate precache_delegate_
;
89 const char kConfigURL
[] = "http://config-url.com";
90 const char kManfiestURLPrefix
[] = "http://manifest-url-prefix.com/";
91 const char kManifestFetchFailureURL
[] =
92 "http://manifest-url-prefix.com/"
93 "http%253A%252F%252Fmanifest-fetch-failure.com%252F";
94 const char kBadManifestURL
[] =
95 "http://manifest-url-prefix.com/http%253A%252F%252Fbad-manifest.com%252F";
96 const char kGoodManifestURL
[] =
97 "http://manifest-url-prefix.com/http%253A%252F%252Fgood-manifest.com%252F";
98 const char kResourceFetchFailureURL
[] = "http://resource-fetch-failure.com";
99 const char kGoodResourceURL
[] = "http://good-resource.com";
100 const char kForcedStartingURLManifestURL
[] =
101 "http://manifest-url-prefix.com/"
102 "http%253A%252F%252Fforced-starting-url.com%252F";
104 TEST_F(PrecacheFetcherTest
, FullPrecache
) {
105 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
106 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
107 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
108 switches::kPrecacheManifestURLPrefix
, kManfiestURLPrefix
);
110 std::list
<GURL
> starting_urls
;
111 starting_urls
.push_back(GURL("http://manifest-fetch-failure.com"));
112 starting_urls
.push_back(GURL("http://bad-manifest.com"));
113 starting_urls
.push_back(GURL("http://good-manifest.com"));
114 starting_urls
.push_back(GURL("http://not-in-top-3.com"));
116 PrecacheConfigurationSettings config
;
117 config
.set_top_sites_count(3);
118 config
.add_forced_starting_url("http://forced-starting-url.com");
119 // Duplicate starting URL, the manifest for this should only be fetched once.
120 config
.add_forced_starting_url("http://good-manifest.com");
122 PrecacheManifest good_manifest
;
123 good_manifest
.add_resource()->set_url(kResourceFetchFailureURL
);
124 good_manifest
.add_resource(); // Resource with no URL, should not be fetched.
125 good_manifest
.add_resource()->set_url(kGoodResourceURL
);
127 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
128 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
129 factory_
.SetFakeResponse(GURL(kManifestFetchFailureURL
), "",
130 net::HTTP_INTERNAL_SERVER_ERROR
,
131 net::URLRequestStatus::FAILED
);
132 factory_
.SetFakeResponse(GURL(kBadManifestURL
), "bad protobuf", net::HTTP_OK
,
133 net::URLRequestStatus::SUCCESS
);
134 factory_
.SetFakeResponse(GURL(kGoodManifestURL
),
135 good_manifest
.SerializeAsString(), net::HTTP_OK
,
136 net::URLRequestStatus::SUCCESS
);
137 factory_
.SetFakeResponse(GURL(kResourceFetchFailureURL
),
138 "", net::HTTP_INTERNAL_SERVER_ERROR
,
139 net::URLRequestStatus::FAILED
);
140 factory_
.SetFakeResponse(GURL(kGoodResourceURL
), "good", net::HTTP_OK
,
141 net::URLRequestStatus::SUCCESS
);
142 factory_
.SetFakeResponse(GURL(kForcedStartingURLManifestURL
),
143 PrecacheManifest().SerializeAsString(), net::HTTP_OK
,
144 net::URLRequestStatus::SUCCESS
);
146 PrecacheFetcher
precache_fetcher(starting_urls
, request_context_
.get(),
147 &precache_delegate_
);
148 precache_fetcher
.Start();
150 base::MessageLoop::current()->RunUntilIdle();
152 std::multiset
<GURL
> expected_requested_urls
;
153 expected_requested_urls
.insert(GURL(kConfigURL
));
154 expected_requested_urls
.insert(GURL(kManifestFetchFailureURL
));
155 expected_requested_urls
.insert(GURL(kBadManifestURL
));
156 expected_requested_urls
.insert(GURL(kGoodManifestURL
));
157 expected_requested_urls
.insert(GURL(kResourceFetchFailureURL
));
158 expected_requested_urls
.insert(GURL(kGoodResourceURL
));
159 expected_requested_urls
.insert(GURL(kForcedStartingURLManifestURL
));
161 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
163 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
166 TEST_F(PrecacheFetcherTest
, ConfigFetchFailure
) {
167 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
168 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
170 std::list
<GURL
> starting_urls(1, GURL("http://starting-url.com"));
172 factory_
.SetFakeResponse(GURL(kConfigURL
), "",
173 net::HTTP_INTERNAL_SERVER_ERROR
,
174 net::URLRequestStatus::FAILED
);
176 PrecacheFetcher
precache_fetcher(starting_urls
, request_context_
.get(),
177 &precache_delegate_
);
178 precache_fetcher
.Start();
180 base::MessageLoop::current()->RunUntilIdle();
182 std::multiset
<GURL
> expected_requested_urls
;
183 expected_requested_urls
.insert(GURL(kConfigURL
));
184 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
186 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
189 TEST_F(PrecacheFetcherTest
, BadConfig
) {
190 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
191 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
193 std::list
<GURL
> starting_urls(1, GURL("http://starting-url.com"));
195 factory_
.SetFakeResponse(GURL(kConfigURL
), "bad protobuf", net::HTTP_OK
,
196 net::URLRequestStatus::SUCCESS
);
198 PrecacheFetcher
precache_fetcher(starting_urls
, request_context_
.get(),
199 &precache_delegate_
);
200 precache_fetcher
.Start();
202 base::MessageLoop::current()->RunUntilIdle();
204 std::multiset
<GURL
> expected_requested_urls
;
205 expected_requested_urls
.insert(GURL(kConfigURL
));
206 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
208 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
211 TEST_F(PrecacheFetcherTest
, Cancel
) {
212 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
213 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
215 std::list
<GURL
> starting_urls(1, GURL("http://starting-url.com"));
217 PrecacheConfigurationSettings config
;
218 config
.set_top_sites_count(1);
220 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
221 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
223 scoped_ptr
<PrecacheFetcher
> precache_fetcher(new PrecacheFetcher(
224 starting_urls
, request_context_
.get(), &precache_delegate_
));
225 precache_fetcher
->Start();
227 // Destroy the PrecacheFetcher to cancel precaching. This should not cause
228 // OnDone to be called on the precache delegate.
229 precache_fetcher
.reset();
231 base::MessageLoop::current()->RunUntilIdle();
233 std::multiset
<GURL
> expected_requested_urls
;
234 expected_requested_urls
.insert(GURL(kConfigURL
));
235 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
237 EXPECT_FALSE(precache_delegate_
.was_on_done_called());
240 #if defined(PRECACHE_CONFIG_SETTINGS_URL)
242 // If the default precache configuration settings URL is defined, then test that
243 // it works with the PrecacheFetcher.
244 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultConfigSettingsURL
) {
245 std::list
<GURL
> starting_urls(1, GURL("http://starting-url.com"));
247 PrecacheConfigurationSettings config
;
248 config
.set_top_sites_count(0);
250 factory_
.SetFakeResponse(GURL(PRECACHE_CONFIG_SETTINGS_URL
),
251 config
.SerializeAsString(), net::HTTP_OK
,
252 net::URLRequestStatus::SUCCESS
);
254 PrecacheFetcher
precache_fetcher(starting_urls
, request_context_
.get(),
255 &precache_delegate_
);
256 precache_fetcher
.Start();
258 base::MessageLoop::current()->RunUntilIdle();
260 std::multiset
<GURL
> expected_requested_urls
;
261 expected_requested_urls
.insert(GURL(PRECACHE_CONFIG_SETTINGS_URL
));
262 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
264 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
267 #endif // PRECACHE_CONFIG_SETTINGS_URL
269 #if defined(PRECACHE_MANIFEST_URL_PREFIX)
271 // If the default precache manifest URL prefix is defined, then test that it
272 // works with the PrecacheFetcher.
273 TEST_F(PrecacheFetcherTest
, PrecacheUsingDefaultManifestURLPrefix
) {
274 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
275 switches::kPrecacheConfigSettingsURL
, kConfigURL
);
277 std::list
<GURL
> starting_urls(1, GURL("http://starting-url.com"));
279 PrecacheConfigurationSettings config
;
280 config
.set_top_sites_count(1);
282 GURL
manifest_url(PRECACHE_MANIFEST_URL_PREFIX
283 "http%253A%252F%252Fstarting-url.com%252F");
285 factory_
.SetFakeResponse(GURL(kConfigURL
), config
.SerializeAsString(),
286 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
287 factory_
.SetFakeResponse(manifest_url
, PrecacheManifest().SerializeAsString(),
288 net::HTTP_OK
, net::URLRequestStatus::SUCCESS
);
290 PrecacheFetcher
precache_fetcher(starting_urls
, request_context_
.get(),
291 &precache_delegate_
);
292 precache_fetcher
.Start();
294 base::MessageLoop::current()->RunUntilIdle();
296 std::multiset
<GURL
> expected_requested_urls
;
297 expected_requested_urls
.insert(GURL(kConfigURL
));
298 expected_requested_urls
.insert(manifest_url
);
299 EXPECT_EQ(expected_requested_urls
, url_callback_
.requested_urls());
301 EXPECT_TRUE(precache_delegate_
.was_on_done_called());
304 #endif // PRECACHE_MANIFEST_URL_PREFIX
308 } // namespace precache