Home | History | Annotate | Download | only in core
      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 
     26 namespace precache {
     27 
     28 namespace {
     29 
     30 class 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 
     59 class 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 
     75 class 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 
     91 const char kConfigURL[] = "http://config-url.com";
     92 const char kManfiestURLPrefix[] = "http://manifest-url-prefix.com/";
     93 const char kManifestFetchFailureURL[] =
     94     "http://manifest-url-prefix.com/"
     95     "http%253A%252F%252Fmanifest-fetch-failure.com%252F";
     96 const char kBadManifestURL[] =
     97     "http://manifest-url-prefix.com/http%253A%252F%252Fbad-manifest.com%252F";
     98 const char kGoodManifestURL[] =
     99     "http://manifest-url-prefix.com/http%253A%252F%252Fgood-manifest.com%252F";
    100 const char kResourceFetchFailureURL[] = "http://resource-fetch-failure.com";
    101 const char kGoodResourceURL[] = "http://good-resource.com";
    102 const char kForcedStartingURLManifestURL[] =
    103     "http://manifest-url-prefix.com/"
    104     "http%253A%252F%252Fforced-starting-url.com%252F";
    105 
    106 TEST_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 
    168 TEST_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 
    191 TEST_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 
    213 TEST_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.
    246 TEST_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.
    275 TEST_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