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_fetcher.h" 6 7#include <list> 8#include <set> 9#include <string> 10 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" 25 26namespace precache { 27 28namespace { 29 30class TestURLFetcherCallback { 31 public: 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)); 38 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); 44 } 45 46 requested_urls_.insert(url); 47 return fetcher.Pass(); 48 } 49 50 const std::multiset<GURL>& requested_urls() const { 51 return requested_urls_; 52 } 53 54 private: 55 // Multiset with one entry for each URL requested. 56 std::multiset<GURL> requested_urls_; 57}; 58 59class TestPrecacheDelegate : public PrecacheFetcher::PrecacheDelegate { 60 public: 61 TestPrecacheDelegate() : was_on_done_called_(false) {} 62 63 virtual void OnDone() OVERRIDE { 64 was_on_done_called_ = true; 65 } 66 67 bool was_on_done_called() const { 68 return was_on_done_called_; 69 } 70 71 private: 72 bool was_on_done_called_; 73}; 74 75class PrecacheFetcherTest : public testing::Test { 76 public: 77 PrecacheFetcherTest() 78 : request_context_(new net::TestURLRequestContextGetter( 79 base::MessageLoopProxy::current())), 80 factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, 81 base::Unretained(&url_callback_))) {} 82 83 protected: 84 base::MessageLoopForUI loop_; 85 scoped_refptr<net::TestURLRequestContextGetter> request_context_; 86 TestURLFetcherCallback url_callback_; 87 net::FakeURLFetcherFactory factory_; 88 TestPrecacheDelegate precache_delegate_; 89}; 90 91const char kConfigURL[] = "http://config-url.com"; 92const char kManfiestURLPrefix[] = "http://manifest-url-prefix.com/"; 93const char kManifestFetchFailureURL[] = 94 "http://manifest-url-prefix.com/" 95 "http%253A%252F%252Fmanifest-fetch-failure.com%252F"; 96const char kBadManifestURL[] = 97 "http://manifest-url-prefix.com/http%253A%252F%252Fbad-manifest.com%252F"; 98const char kGoodManifestURL[] = 99 "http://manifest-url-prefix.com/http%253A%252F%252Fgood-manifest.com%252F"; 100const char kResourceFetchFailureURL[] = "http://resource-fetch-failure.com"; 101const char kGoodResourceURL[] = "http://good-resource.com"; 102const char kForcedStartingURLManifestURL[] = 103 "http://manifest-url-prefix.com/" 104 "http%253A%252F%252Fforced-starting-url.com%252F"; 105 106TEST_F(PrecacheFetcherTest, FullPrecache) { 107 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 108 switches::kPrecacheConfigSettingsURL, kConfigURL); 109 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 110 switches::kPrecacheManifestURLPrefix, kManfiestURLPrefix); 111 112 std::list<GURL> starting_urls; 113 starting_urls.push_back(GURL("http://manifest-fetch-failure.com")); 114 starting_urls.push_back(GURL("http://bad-manifest.com")); 115 starting_urls.push_back(GURL("http://good-manifest.com")); 116 starting_urls.push_back(GURL("http://not-in-top-3.com")); 117 118 PrecacheConfigurationSettings config; 119 config.set_top_sites_count(3); 120 config.add_forced_starting_url("http://forced-starting-url.com"); 121 // Duplicate starting URL, the manifest for this should only be fetched once. 122 config.add_forced_starting_url("http://good-manifest.com"); 123 124 PrecacheManifest good_manifest; 125 good_manifest.add_resource()->set_url(kResourceFetchFailureURL); 126 good_manifest.add_resource(); // Resource with no URL, should not be fetched. 127 good_manifest.add_resource()->set_url(kGoodResourceURL); 128 129 factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(), 130 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 131 factory_.SetFakeResponse(GURL(kManifestFetchFailureURL), "", 132 net::HTTP_INTERNAL_SERVER_ERROR, 133 net::URLRequestStatus::FAILED); 134 factory_.SetFakeResponse(GURL(kBadManifestURL), "bad protobuf", net::HTTP_OK, 135 net::URLRequestStatus::SUCCESS); 136 factory_.SetFakeResponse(GURL(kGoodManifestURL), 137 good_manifest.SerializeAsString(), net::HTTP_OK, 138 net::URLRequestStatus::SUCCESS); 139 factory_.SetFakeResponse(GURL(kResourceFetchFailureURL), 140 "", net::HTTP_INTERNAL_SERVER_ERROR, 141 net::URLRequestStatus::FAILED); 142 factory_.SetFakeResponse(GURL(kGoodResourceURL), "good", net::HTTP_OK, 143 net::URLRequestStatus::SUCCESS); 144 factory_.SetFakeResponse(GURL(kForcedStartingURLManifestURL), 145 PrecacheManifest().SerializeAsString(), net::HTTP_OK, 146 net::URLRequestStatus::SUCCESS); 147 148 PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(), 149 &precache_delegate_); 150 precache_fetcher.Start(); 151 152 base::MessageLoop::current()->RunUntilIdle(); 153 154 std::multiset<GURL> expected_requested_urls; 155 expected_requested_urls.insert(GURL(kConfigURL)); 156 expected_requested_urls.insert(GURL(kManifestFetchFailureURL)); 157 expected_requested_urls.insert(GURL(kBadManifestURL)); 158 expected_requested_urls.insert(GURL(kGoodManifestURL)); 159 expected_requested_urls.insert(GURL(kResourceFetchFailureURL)); 160 expected_requested_urls.insert(GURL(kGoodResourceURL)); 161 expected_requested_urls.insert(GURL(kForcedStartingURLManifestURL)); 162 163 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 164 165 EXPECT_TRUE(precache_delegate_.was_on_done_called()); 166} 167 168TEST_F(PrecacheFetcherTest, ConfigFetchFailure) { 169 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 170 switches::kPrecacheConfigSettingsURL, kConfigURL); 171 172 std::list<GURL> starting_urls(1, GURL("http://starting-url.com")); 173 174 factory_.SetFakeResponse(GURL(kConfigURL), "", 175 net::HTTP_INTERNAL_SERVER_ERROR, 176 net::URLRequestStatus::FAILED); 177 178 PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(), 179 &precache_delegate_); 180 precache_fetcher.Start(); 181 182 base::MessageLoop::current()->RunUntilIdle(); 183 184 std::multiset<GURL> expected_requested_urls; 185 expected_requested_urls.insert(GURL(kConfigURL)); 186 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 187 188 EXPECT_TRUE(precache_delegate_.was_on_done_called()); 189} 190 191TEST_F(PrecacheFetcherTest, BadConfig) { 192 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 193 switches::kPrecacheConfigSettingsURL, kConfigURL); 194 195 std::list<GURL> starting_urls(1, GURL("http://starting-url.com")); 196 197 factory_.SetFakeResponse(GURL(kConfigURL), "bad protobuf", net::HTTP_OK, 198 net::URLRequestStatus::SUCCESS); 199 200 PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(), 201 &precache_delegate_); 202 precache_fetcher.Start(); 203 204 base::MessageLoop::current()->RunUntilIdle(); 205 206 std::multiset<GURL> expected_requested_urls; 207 expected_requested_urls.insert(GURL(kConfigURL)); 208 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 209 210 EXPECT_TRUE(precache_delegate_.was_on_done_called()); 211} 212 213TEST_F(PrecacheFetcherTest, Cancel) { 214 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 215 switches::kPrecacheConfigSettingsURL, kConfigURL); 216 217 std::list<GURL> starting_urls(1, GURL("http://starting-url.com")); 218 219 PrecacheConfigurationSettings config; 220 config.set_top_sites_count(1); 221 222 factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(), 223 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 224 225 scoped_ptr<PrecacheFetcher> precache_fetcher(new PrecacheFetcher( 226 starting_urls, request_context_.get(), &precache_delegate_)); 227 precache_fetcher->Start(); 228 229 // Destroy the PrecacheFetcher to cancel precaching. This should not cause 230 // OnDone to be called on the precache delegate. 231 precache_fetcher.reset(); 232 233 base::MessageLoop::current()->RunUntilIdle(); 234 235 std::multiset<GURL> expected_requested_urls; 236 expected_requested_urls.insert(GURL(kConfigURL)); 237 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 238 239 EXPECT_FALSE(precache_delegate_.was_on_done_called()); 240} 241 242#if defined(PRECACHE_CONFIG_SETTINGS_URL) 243 244// If the default precache configuration settings URL is defined, then test that 245// it works with the PrecacheFetcher. 246TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultConfigSettingsURL) { 247 std::list<GURL> starting_urls(1, GURL("http://starting-url.com")); 248 249 PrecacheConfigurationSettings config; 250 config.set_top_sites_count(0); 251 252 factory_.SetFakeResponse(GURL(PRECACHE_CONFIG_SETTINGS_URL), 253 config.SerializeAsString(), net::HTTP_OK, 254 net::URLRequestStatus::SUCCESS); 255 256 PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(), 257 &precache_delegate_); 258 precache_fetcher.Start(); 259 260 base::MessageLoop::current()->RunUntilIdle(); 261 262 std::multiset<GURL> expected_requested_urls; 263 expected_requested_urls.insert(GURL(PRECACHE_CONFIG_SETTINGS_URL)); 264 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 265 266 EXPECT_TRUE(precache_delegate_.was_on_done_called()); 267} 268 269#endif // PRECACHE_CONFIG_SETTINGS_URL 270 271#if defined(PRECACHE_MANIFEST_URL_PREFIX) 272 273// If the default precache manifest URL prefix is defined, then test that it 274// works with the PrecacheFetcher. 275TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultManifestURLPrefix) { 276 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 277 switches::kPrecacheConfigSettingsURL, kConfigURL); 278 279 std::list<GURL> starting_urls(1, GURL("http://starting-url.com")); 280 281 PrecacheConfigurationSettings config; 282 config.set_top_sites_count(1); 283 284 GURL manifest_url(PRECACHE_MANIFEST_URL_PREFIX 285 "http%253A%252F%252Fstarting-url.com%252F"); 286 287 factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(), 288 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 289 factory_.SetFakeResponse(manifest_url, PrecacheManifest().SerializeAsString(), 290 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 291 292 PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(), 293 &precache_delegate_); 294 precache_fetcher.Start(); 295 296 base::MessageLoop::current()->RunUntilIdle(); 297 298 std::multiset<GURL> expected_requested_urls; 299 expected_requested_urls.insert(GURL(kConfigURL)); 300 expected_requested_urls.insert(manifest_url); 301 EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls()); 302 303 EXPECT_TRUE(precache_delegate_.was_on_done_called()); 304} 305 306#endif // PRECACHE_MANIFEST_URL_PREFIX 307 308} // namespace 309 310} // namespace precache 311