Home | History | Annotate | Download | only in predictors
      1 // Copyright (c) 2012 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 "base/memory/ref_counted.h"
      6 #include "base/memory/scoped_ptr.h"
      7 #include "base/message_loop/message_loop.h"
      8 #include "chrome/browser/predictors/resource_prefetcher.h"
      9 #include "chrome/browser/predictors/resource_prefetcher_manager.h"
     10 #include "chrome/test/base/testing_profile.h"
     11 #include "content/public/test/test_browser_thread.h"
     12 #include "net/url_request/url_request.h"
     13 #include "net/url_request/url_request_test_util.h"
     14 #include "testing/gmock/include/gmock/gmock.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 using testing::Eq;
     18 using testing::Property;
     19 
     20 namespace predictors {
     21 
     22 // Wrapper over the ResourcePrefetcher that stubs out the StartURLRequest call
     23 // since we do not want to do network fetches in this unittest.
     24 class TestResourcePrefetcher : public ResourcePrefetcher {
     25  public:
     26   TestResourcePrefetcher(ResourcePrefetcher::Delegate* delegate,
     27                          const ResourcePrefetchPredictorConfig& config,
     28                          const NavigationID& navigation_id,
     29                          PrefetchKeyType key_type,
     30                          scoped_ptr<RequestVector> requests)
     31       : ResourcePrefetcher(delegate, config, navigation_id,
     32                            key_type, requests.Pass()) { }
     33 
     34   virtual ~TestResourcePrefetcher() { }
     35 
     36   MOCK_METHOD1(StartURLRequest, void(net::URLRequest* request));
     37 
     38   void ReadFullResponse(net::URLRequest* request) OVERRIDE {
     39     FinishRequest(request, Request::PREFETCH_STATUS_FROM_CACHE);
     40   }
     41 
     42  private:
     43   DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcher);
     44 };
     45 
     46 
     47 // Delegate for ResourcePrefetcher.
     48 class TestResourcePrefetcherDelegate : public ResourcePrefetcher::Delegate {
     49  public:
     50   explicit TestResourcePrefetcherDelegate(base::MessageLoop* loop)
     51       : request_context_getter_(new net::TestURLRequestContextGetter(
     52           loop->message_loop_proxy())) { }
     53   ~TestResourcePrefetcherDelegate() { }
     54 
     55   virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
     56     return request_context_getter_->GetURLRequestContext();
     57   }
     58 
     59   MOCK_METHOD2(ResourcePrefetcherFinished,
     60                void(ResourcePrefetcher* prefetcher,
     61                     ResourcePrefetcher::RequestVector* requests));
     62 
     63  private:
     64   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(TestResourcePrefetcherDelegate);
     67 };
     68 
     69 
     70 // The following unittest tests most of the ResourcePrefetcher except for:
     71 // 1. Call to ReadFullResponse. There does not seem to be a good way to test the
     72 //    function in a unittest, and probably requires a browser_test.
     73 // 2. Setting of the Prefetch status for cache vs non cache.
     74 class ResourcePrefetcherTest : public testing::Test {
     75  public:
     76   ResourcePrefetcherTest();
     77   virtual ~ResourcePrefetcherTest();
     78 
     79  protected:
     80   typedef ResourcePrefetcher::Request Request;
     81 
     82   void AddStartUrlRequestExpectation(const std::string& url) {
     83     EXPECT_CALL(*prefetcher_,
     84                 StartURLRequest(Property(&net::URLRequest::original_url,
     85                                          Eq(GURL(url)))));
     86   }
     87 
     88   void CheckPrefetcherState(size_t inflight, size_t queue, size_t host) {
     89     EXPECT_EQ(prefetcher_->inflight_requests_.size(), inflight);
     90     EXPECT_EQ(prefetcher_->request_queue_.size(), queue);
     91     EXPECT_EQ(prefetcher_->host_inflight_counts_.size(), host);
     92   }
     93 
     94   net::URLRequest* GetInFlightRequest(const std::string& url_str) {
     95     GURL url(url_str);
     96 
     97     for (std::list<Request*>::const_iterator it =
     98          prefetcher_->request_queue_.begin();
     99          it != prefetcher_->request_queue_.end(); ++it) {
    100       EXPECT_NE((*it)->resource_url, url);
    101     }
    102     for (std::map<net::URLRequest*, Request*>::const_iterator it =
    103          prefetcher_->inflight_requests_.begin();
    104          it != prefetcher_->inflight_requests_.end(); ++it) {
    105       if (it->first->original_url() == url)
    106         return it->first;
    107     }
    108     EXPECT_TRUE(false) << "Infligh request not found: " << url_str;
    109     return NULL;
    110   }
    111 
    112 
    113   void OnReceivedRedirect(const std::string& url) {
    114     prefetcher_->OnReceivedRedirect(
    115         GetInFlightRequest(url), GURL(std::string()), NULL);
    116   }
    117   void OnAuthRequired(const std::string& url) {
    118     prefetcher_->OnAuthRequired(GetInFlightRequest(url), NULL);
    119   }
    120   void OnCertificateRequested(const std::string& url) {
    121     prefetcher_->OnCertificateRequested(GetInFlightRequest(url), NULL);
    122   }
    123   void OnSSLCertificateError(const std::string& url) {
    124     prefetcher_->OnSSLCertificateError(GetInFlightRequest(url),
    125                                        net::SSLInfo(), false);
    126   }
    127   void OnResponse(const std::string& url) {
    128     prefetcher_->OnResponseStarted(GetInFlightRequest(url));
    129   }
    130 
    131   base::MessageLoop loop_;
    132   content::TestBrowserThread io_thread_;
    133   ResourcePrefetchPredictorConfig config_;
    134   TestResourcePrefetcherDelegate prefetcher_delegate_;
    135   scoped_ptr<TestResourcePrefetcher> prefetcher_;
    136 
    137  private:
    138   DISALLOW_COPY_AND_ASSIGN(ResourcePrefetcherTest);
    139 };
    140 
    141 ResourcePrefetcherTest::ResourcePrefetcherTest()
    142     : loop_(base::MessageLoop::TYPE_IO),
    143       io_thread_(content::BrowserThread::IO, &loop_),
    144       prefetcher_delegate_(&loop_) {
    145   config_.max_prefetches_inflight_per_navigation = 5;
    146   config_.max_prefetches_inflight_per_host_per_navigation = 2;
    147 }
    148 
    149 ResourcePrefetcherTest::~ResourcePrefetcherTest() {
    150 }
    151 
    152 TEST_F(ResourcePrefetcherTest, TestPrefetcherFinishes) {
    153   scoped_ptr<ResourcePrefetcher::RequestVector> requests(
    154       new ResourcePrefetcher::RequestVector);
    155   requests->push_back(new ResourcePrefetcher::Request(GURL(
    156       "http://www.google.com/resource1.html")));
    157   requests->push_back(new ResourcePrefetcher::Request(GURL(
    158       "http://www.google.com/resource2.png")));
    159   requests->push_back(new ResourcePrefetcher::Request(GURL(
    160       "http://yahoo.com/resource1.png")));
    161   requests->push_back(new ResourcePrefetcher::Request(GURL(
    162       "http://yahoo.com/resource2.png")));
    163   requests->push_back(new ResourcePrefetcher::Request(GURL(
    164       "http://yahoo.com/resource3.png")));
    165   requests->push_back(new ResourcePrefetcher::Request(GURL(
    166       "http://m.google.com/resource1.jpg")));
    167   requests->push_back(new ResourcePrefetcher::Request(GURL(
    168       "http://www.google.com/resource3.html")));
    169   requests->push_back(new ResourcePrefetcher::Request(GURL(
    170       "http://m.google.com/resource2.html")));
    171   requests->push_back(new ResourcePrefetcher::Request(GURL(
    172       "http://m.google.com/resource3.css")));
    173   requests->push_back(new ResourcePrefetcher::Request(GURL(
    174       "http://m.google.com/resource4.png")));
    175   requests->push_back(new ResourcePrefetcher::Request(GURL(
    176       "http://yahoo.com/resource4.png")));
    177   requests->push_back(new ResourcePrefetcher::Request(GURL(
    178       "http://yahoo.com/resource5.png")));
    179 
    180   NavigationID navigation_id;
    181   navigation_id.render_process_id = 1;
    182   navigation_id.render_view_id = 2;
    183   navigation_id.main_frame_url = GURL("http://www.google.com");
    184 
    185   // Needed later for comparison.
    186   ResourcePrefetcher::RequestVector* requests_ptr = requests.get();
    187 
    188   prefetcher_.reset(new TestResourcePrefetcher(&prefetcher_delegate_,
    189                                                config_,
    190                                                navigation_id,
    191                                                PREFETCH_KEY_TYPE_URL,
    192                                                requests.Pass()));
    193 
    194   // Starting the prefetcher maxes out the number of possible requests.
    195   AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
    196   AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
    197   AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
    198   AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
    199   AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
    200 
    201   prefetcher_->Start();
    202   CheckPrefetcherState(5, 7, 3);
    203 
    204   AddStartUrlRequestExpectation("http://m.google.com/resource2.html");
    205   OnResponse("http://m.google.com/resource1.jpg");
    206   CheckPrefetcherState(5, 6, 3);
    207 
    208   AddStartUrlRequestExpectation("http://www.google.com/resource3.html");
    209   OnSSLCertificateError("http://www.google.com/resource1.html");
    210   CheckPrefetcherState(5, 5, 3);
    211 
    212   AddStartUrlRequestExpectation("http://m.google.com/resource3.css");
    213   OnResponse("http://m.google.com/resource2.html");
    214   CheckPrefetcherState(5, 4, 3);
    215 
    216   AddStartUrlRequestExpectation("http://m.google.com/resource4.png");
    217   OnReceivedRedirect("http://www.google.com/resource3.html");
    218   CheckPrefetcherState(5, 3, 3);
    219 
    220   OnResponse("http://www.google.com/resource2.png");
    221   CheckPrefetcherState(4, 3, 2);
    222 
    223   AddStartUrlRequestExpectation("http://yahoo.com/resource3.png");
    224   OnReceivedRedirect("http://yahoo.com/resource2.png");
    225   CheckPrefetcherState(4, 2, 2);
    226 
    227   AddStartUrlRequestExpectation("http://yahoo.com/resource4.png");
    228   OnResponse("http://yahoo.com/resource1.png");
    229   CheckPrefetcherState(4, 1, 2);
    230 
    231   AddStartUrlRequestExpectation("http://yahoo.com/resource5.png");
    232   OnResponse("http://yahoo.com/resource4.png");
    233   CheckPrefetcherState(4, 0, 2);
    234 
    235   OnResponse("http://yahoo.com/resource5.png");
    236   CheckPrefetcherState(3, 0, 2);
    237 
    238   OnCertificateRequested("http://m.google.com/resource4.png");
    239   CheckPrefetcherState(2, 0, 2);
    240 
    241   OnAuthRequired("http://m.google.com/resource3.css");
    242   CheckPrefetcherState(1, 0, 1);
    243 
    244   // Expect the final call.
    245   EXPECT_CALL(prefetcher_delegate_,
    246               ResourcePrefetcherFinished(Eq(prefetcher_.get()),
    247                                          Eq(requests_ptr)));
    248 
    249   OnResponse("http://yahoo.com/resource3.png");
    250   CheckPrefetcherState(0, 0, 0);
    251 
    252   // Check the prefetch status.
    253   EXPECT_EQ((*requests_ptr)[0]->prefetch_status,
    254             Request::PREFETCH_STATUS_CERT_ERROR);
    255   EXPECT_EQ((*requests_ptr)[1]->prefetch_status,
    256             Request::PREFETCH_STATUS_FROM_CACHE);
    257   EXPECT_EQ((*requests_ptr)[2]->prefetch_status,
    258             Request::PREFETCH_STATUS_FROM_CACHE);
    259   EXPECT_EQ((*requests_ptr)[3]->prefetch_status,
    260             Request::PREFETCH_STATUS_REDIRECTED);
    261   EXPECT_EQ((*requests_ptr)[4]->prefetch_status,
    262             Request::PREFETCH_STATUS_FROM_CACHE);
    263   EXPECT_EQ((*requests_ptr)[5]->prefetch_status,
    264             Request::PREFETCH_STATUS_FROM_CACHE);
    265   EXPECT_EQ((*requests_ptr)[6]->prefetch_status,
    266             Request::PREFETCH_STATUS_REDIRECTED);
    267   EXPECT_EQ((*requests_ptr)[7]->prefetch_status,
    268             Request::PREFETCH_STATUS_FROM_CACHE);
    269   EXPECT_EQ((*requests_ptr)[8]->prefetch_status,
    270             Request::PREFETCH_STATUS_AUTH_REQUIRED);
    271   EXPECT_EQ((*requests_ptr)[9]->prefetch_status,
    272             Request::PREFETCH_STATUS_CERT_REQUIRED);
    273   EXPECT_EQ((*requests_ptr)[10]->prefetch_status,
    274             Request::PREFETCH_STATUS_FROM_CACHE);
    275   EXPECT_EQ((*requests_ptr)[11]->prefetch_status,
    276             Request::PREFETCH_STATUS_FROM_CACHE);
    277 
    278   delete requests_ptr;
    279 }
    280 
    281 TEST_F(ResourcePrefetcherTest, TestPrefetcherStopped) {
    282   scoped_ptr<ResourcePrefetcher::RequestVector> requests(
    283       new ResourcePrefetcher::RequestVector);
    284   requests->push_back(new ResourcePrefetcher::Request(GURL(
    285       "http://www.google.com/resource1.html")));
    286   requests->push_back(new ResourcePrefetcher::Request(GURL(
    287       "http://www.google.com/resource2.png")));
    288   requests->push_back(new ResourcePrefetcher::Request(GURL(
    289       "http://yahoo.com/resource1.png")));
    290   requests->push_back(new ResourcePrefetcher::Request(GURL(
    291       "http://yahoo.com/resource2.png")));
    292   requests->push_back(new ResourcePrefetcher::Request(GURL(
    293       "http://yahoo.com/resource3.png")));
    294   requests->push_back(new ResourcePrefetcher::Request(GURL(
    295       "http://m.google.com/resource1.jpg")));
    296 
    297   NavigationID navigation_id;
    298   navigation_id.render_process_id = 1;
    299   navigation_id.render_view_id = 2;
    300   navigation_id.main_frame_url = GURL("http://www.google.com");
    301 
    302   // Needed later for comparison.
    303   ResourcePrefetcher::RequestVector* requests_ptr = requests.get();
    304 
    305   prefetcher_.reset(new TestResourcePrefetcher(&prefetcher_delegate_,
    306                                                config_,
    307                                                navigation_id,
    308                                                PREFETCH_KEY_TYPE_HOST,
    309                                                requests.Pass()));
    310 
    311   // Starting the prefetcher maxes out the number of possible requests.
    312   AddStartUrlRequestExpectation("http://www.google.com/resource1.html");
    313   AddStartUrlRequestExpectation("http://www.google.com/resource2.png");
    314   AddStartUrlRequestExpectation("http://yahoo.com/resource1.png");
    315   AddStartUrlRequestExpectation("http://yahoo.com/resource2.png");
    316   AddStartUrlRequestExpectation("http://m.google.com/resource1.jpg");
    317 
    318   prefetcher_->Start();
    319   CheckPrefetcherState(5, 1, 3);
    320 
    321   OnResponse("http://www.google.com/resource1.html");
    322   CheckPrefetcherState(4, 1, 3);
    323 
    324   prefetcher_->Stop();  // No more queueing.
    325 
    326   OnResponse("http://www.google.com/resource2.png");
    327   CheckPrefetcherState(3, 1, 2);
    328 
    329   OnResponse("http://yahoo.com/resource1.png");
    330   CheckPrefetcherState(2, 1, 2);
    331 
    332   OnResponse("http://yahoo.com/resource2.png");
    333   CheckPrefetcherState(1, 1, 1);
    334 
    335   // Expect the final call.
    336   EXPECT_CALL(prefetcher_delegate_,
    337               ResourcePrefetcherFinished(Eq(prefetcher_.get()),
    338                                          Eq(requests_ptr)));
    339 
    340   OnResponse("http://m.google.com/resource1.jpg");
    341   CheckPrefetcherState(0, 1, 0);
    342 
    343   delete requests_ptr;
    344 }
    345 
    346 }  // namespace predictors
    347