Home | History | Annotate | Download | only in prerender
      1 // Copyright (c) 2011 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/time.h"
      6 #include "chrome/browser/prerender/prerender_contents.h"
      7 #include "chrome/browser/prerender/prerender_manager.h"
      8 #include "content/browser/browser_thread.h"
      9 #include "content/browser/renderer_host/render_view_host.h"
     10 #include "content/browser/renderer_host/render_process_host.h"
     11 #include "googleurl/src/gurl.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace prerender {
     15 
     16 namespace {
     17 
     18 class DummyPrerenderContents : public PrerenderContents {
     19  public:
     20   DummyPrerenderContents(PrerenderManager* prerender_manager,
     21                          const GURL& url,
     22                          FinalStatus expected_final_status)
     23       : PrerenderContents(prerender_manager, NULL, url,
     24                           std::vector<GURL>(), GURL()),
     25         has_started_(false),
     26         expected_final_status_(expected_final_status) {
     27   }
     28 
     29   DummyPrerenderContents(PrerenderManager* prerender_manager,
     30                          const GURL& url,
     31                          const std::vector<GURL> alias_urls,
     32                          FinalStatus expected_final_status)
     33       : PrerenderContents(prerender_manager, NULL, url, alias_urls, GURL()),
     34         has_started_(false),
     35         expected_final_status_(expected_final_status) {
     36   }
     37 
     38   virtual ~DummyPrerenderContents() {
     39     EXPECT_EQ(expected_final_status_, final_status());
     40   }
     41 
     42   virtual void StartPrerendering() OVERRIDE {
     43     has_started_ = true;
     44   }
     45 
     46   virtual bool GetChildId(int* child_id) const OVERRIDE {
     47     *child_id = 0;
     48     return true;
     49   }
     50 
     51   virtual bool GetRouteId(int* route_id) const OVERRIDE {
     52     *route_id = 0;
     53     return true;
     54   }
     55 
     56   bool has_started() const { return has_started_; }
     57 
     58  private:
     59   bool has_started_;
     60   FinalStatus expected_final_status_;
     61 };
     62 
     63 class TestPrerenderManager : public PrerenderManager {
     64  public:
     65   TestPrerenderManager()
     66       : PrerenderManager(NULL),
     67         time_(base::Time::Now()),
     68         time_ticks_(base::TimeTicks::Now()),
     69         next_pc_(NULL) {
     70     rate_limit_enabled_ = false;
     71   }
     72 
     73   void AdvanceTime(base::TimeDelta delta) {
     74     time_ += delta;
     75   }
     76 
     77   void AdvanceTimeTicks(base::TimeDelta delta) {
     78     time_ticks_ += delta;
     79   }
     80 
     81   void SetNextPrerenderContents(PrerenderContents* pc) {
     82     next_pc_.reset(pc);
     83   }
     84 
     85   // Shorthand to add a simple preload with no aliases.
     86   bool AddSimplePreload(const GURL& url) {
     87     return AddPreload(url, std::vector<GURL>(), GURL());
     88   }
     89 
     90   bool IsPendingEntry(const GURL& url) {
     91     return (PrerenderManager::FindPendingEntry(url) != NULL);
     92   }
     93 
     94   void set_rate_limit_enabled(bool enabled) { rate_limit_enabled_ = true; }
     95 
     96   PrerenderContents* next_pc() { return next_pc_.get(); }
     97 
     98  protected:
     99   virtual ~TestPrerenderManager() {
    100     if (next_pc()) {
    101       next_pc()->set_final_status(
    102           FINAL_STATUS_MANAGER_SHUTDOWN);
    103     }
    104   }
    105 
    106  private:
    107   virtual base::Time GetCurrentTime() const OVERRIDE {
    108     return time_;
    109   }
    110 
    111   virtual base::TimeTicks GetCurrentTimeTicks() const OVERRIDE {
    112     return time_ticks_;
    113   }
    114 
    115   virtual PrerenderContents* CreatePrerenderContents(
    116       const GURL& url,
    117       const std::vector<GURL>& alias_urls,
    118       const GURL& referrer) OVERRIDE {
    119     DCHECK(next_pc_.get());
    120     return next_pc_.release();
    121   }
    122 
    123   base::Time time_;
    124   base::TimeTicks time_ticks_;
    125   scoped_ptr<PrerenderContents> next_pc_;
    126 };
    127 
    128 }  // namespace
    129 
    130 class PrerenderManagerTest : public testing::Test {
    131  public:
    132   PrerenderManagerTest() : prerender_manager_(new TestPrerenderManager()),
    133                            ui_thread_(BrowserThread::UI, &message_loop_) {
    134   }
    135 
    136  protected:
    137   scoped_refptr<TestPrerenderManager> prerender_manager_;
    138 
    139  private:
    140   // Needed to pass PrerenderManager's DCHECKs.
    141   MessageLoop message_loop_;
    142   BrowserThread ui_thread_;
    143 };
    144 
    145 TEST_F(PrerenderManagerTest, EmptyTest) {
    146   GURL url("http://www.google.com/");
    147   EXPECT_FALSE(prerender_manager_->MaybeUsePreloadedPage(NULL, url));
    148 }
    149 
    150 TEST_F(PrerenderManagerTest, FoundTest) {
    151   GURL url("http://www.google.com/");
    152   DummyPrerenderContents* pc =
    153       new DummyPrerenderContents(prerender_manager_.get(),
    154                                  url,
    155                                  FINAL_STATUS_USED);
    156   prerender_manager_->SetNextPrerenderContents(pc);
    157   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    158   EXPECT_TRUE(pc->has_started());
    159   ASSERT_EQ(pc, prerender_manager_->GetEntry(url));
    160   pc->set_final_status(FINAL_STATUS_USED);
    161   delete pc;
    162 }
    163 
    164 // Make sure that if queue a request, and a second prerender request for the
    165 // same URL comes in, that we drop the second request and keep the first one.
    166 TEST_F(PrerenderManagerTest, DropSecondRequestTest) {
    167   GURL url("http://www.google.com/");
    168   DummyPrerenderContents* pc =
    169       new DummyPrerenderContents(prerender_manager_.get(), url,
    170                                  FINAL_STATUS_USED);
    171   DummyPrerenderContents* null = NULL;
    172   prerender_manager_->SetNextPrerenderContents(pc);
    173   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    174   EXPECT_EQ(null, prerender_manager_->next_pc());
    175   EXPECT_TRUE(pc->has_started());
    176   DummyPrerenderContents* pc1 =
    177       new DummyPrerenderContents(
    178           prerender_manager_.get(), url,
    179           FINAL_STATUS_MANAGER_SHUTDOWN);
    180   prerender_manager_->SetNextPrerenderContents(pc1);
    181   EXPECT_FALSE(prerender_manager_->AddSimplePreload(url));
    182   EXPECT_EQ(pc1, prerender_manager_->next_pc());
    183   EXPECT_FALSE(pc1->has_started());
    184   ASSERT_EQ(pc, prerender_manager_->GetEntry(url));
    185   pc->set_final_status(FINAL_STATUS_USED);
    186   delete pc;
    187 }
    188 
    189 // Ensure that we expire a prerendered page after the max. permitted time.
    190 TEST_F(PrerenderManagerTest, ExpireTest) {
    191   GURL url("http://www.google.com/");
    192   DummyPrerenderContents* pc =
    193       new DummyPrerenderContents(prerender_manager_.get(), url,
    194                                  FINAL_STATUS_TIMED_OUT);
    195   DummyPrerenderContents* null = NULL;
    196   prerender_manager_->SetNextPrerenderContents(pc);
    197   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    198   EXPECT_EQ(null, prerender_manager_->next_pc());
    199   EXPECT_TRUE(pc->has_started());
    200   prerender_manager_->AdvanceTime(prerender_manager_->max_prerender_age()
    201                                   + base::TimeDelta::FromSeconds(1));
    202   ASSERT_EQ(null, prerender_manager_->GetEntry(url));
    203 }
    204 
    205 // LRU Test.  Make sure that if we prerender more than one request, that
    206 // the oldest one will be dropped.
    207 TEST_F(PrerenderManagerTest, DropOldestRequestTest) {
    208   GURL url("http://www.google.com/");
    209   DummyPrerenderContents* pc =
    210       new DummyPrerenderContents(prerender_manager_.get(), url,
    211                                  FINAL_STATUS_EVICTED);
    212   DummyPrerenderContents* null = NULL;
    213   prerender_manager_->SetNextPrerenderContents(pc);
    214   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    215   EXPECT_EQ(null, prerender_manager_->next_pc());
    216   EXPECT_TRUE(pc->has_started());
    217   GURL url1("http://news.google.com/");
    218   DummyPrerenderContents* pc1 =
    219       new DummyPrerenderContents(prerender_manager_.get(), url1,
    220                                  FINAL_STATUS_USED);
    221   prerender_manager_->SetNextPrerenderContents(pc1);
    222   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url1));
    223   EXPECT_EQ(null, prerender_manager_->next_pc());
    224   EXPECT_TRUE(pc1->has_started());
    225   ASSERT_EQ(null, prerender_manager_->GetEntry(url));
    226   ASSERT_EQ(pc1, prerender_manager_->GetEntry(url1));
    227   pc1->set_final_status(FINAL_STATUS_USED);
    228   delete pc1;
    229 }
    230 
    231 // Two element prerender test.  Ensure that the LRU operates correctly if we
    232 // permit 2 elements to be kept prerendered.
    233 TEST_F(PrerenderManagerTest, TwoElementPrerenderTest) {
    234   prerender_manager_->set_max_elements(2);
    235   GURL url("http://www.google.com/");
    236   DummyPrerenderContents* pc =
    237       new DummyPrerenderContents(prerender_manager_.get(), url,
    238                                  FINAL_STATUS_EVICTED);
    239   DummyPrerenderContents* null = NULL;
    240   prerender_manager_->SetNextPrerenderContents(pc);
    241   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    242   EXPECT_EQ(null, prerender_manager_->next_pc());
    243   EXPECT_TRUE(pc->has_started());
    244   GURL url1("http://news.google.com/");
    245   DummyPrerenderContents* pc1 =
    246       new DummyPrerenderContents(prerender_manager_.get(),  url1,
    247                                  FINAL_STATUS_USED);
    248   prerender_manager_->SetNextPrerenderContents(pc1);
    249   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url1));
    250   EXPECT_EQ(null, prerender_manager_->next_pc());
    251   EXPECT_TRUE(pc1->has_started());
    252   GURL url2("http://images.google.com/");
    253   DummyPrerenderContents* pc2 =
    254       new DummyPrerenderContents(prerender_manager_.get(), url2,
    255                                  FINAL_STATUS_USED);
    256   prerender_manager_->SetNextPrerenderContents(pc2);
    257   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url2));
    258   EXPECT_EQ(null, prerender_manager_->next_pc());
    259   EXPECT_TRUE(pc2->has_started());
    260   ASSERT_EQ(null, prerender_manager_->GetEntry(url));
    261   ASSERT_EQ(pc1, prerender_manager_->GetEntry(url1));
    262   ASSERT_EQ(pc2, prerender_manager_->GetEntry(url2));
    263   pc1->set_final_status(FINAL_STATUS_USED);
    264   delete pc1;
    265   pc2->set_final_status(FINAL_STATUS_USED);
    266   delete pc2;
    267 }
    268 
    269 TEST_F(PrerenderManagerTest, AliasURLTest) {
    270   GURL url("http://www.google.com/");
    271   GURL alias_url1("http://www.google.com/index.html");
    272   GURL alias_url2("http://google.com/");
    273   GURL not_an_alias_url("http://google.com/index.html");
    274   std::vector<GURL> alias_urls;
    275   alias_urls.push_back(alias_url1);
    276   alias_urls.push_back(alias_url2);
    277   DummyPrerenderContents* pc =
    278       new DummyPrerenderContents(prerender_manager_.get(), url, alias_urls,
    279                                  FINAL_STATUS_USED);
    280   // Test that all of the aliases work, but nont_an_alias_url does not.
    281   prerender_manager_->SetNextPrerenderContents(pc);
    282   EXPECT_TRUE(prerender_manager_->AddPreload(url, alias_urls, GURL()));
    283   ASSERT_EQ(NULL, prerender_manager_->GetEntry(not_an_alias_url));
    284   ASSERT_EQ(pc, prerender_manager_->GetEntry(alias_url1));
    285   prerender_manager_->SetNextPrerenderContents(pc);
    286   EXPECT_TRUE(prerender_manager_->AddPreload(url, alias_urls, GURL()));
    287   ASSERT_EQ(pc, prerender_manager_->GetEntry(alias_url2));
    288   prerender_manager_->SetNextPrerenderContents(pc);
    289   EXPECT_TRUE(prerender_manager_->AddPreload(url, alias_urls, GURL()));
    290   ASSERT_EQ(pc, prerender_manager_->GetEntry(url));
    291 
    292   // Test that alias URLs can not be added.
    293   prerender_manager_->SetNextPrerenderContents(pc);
    294   EXPECT_TRUE(prerender_manager_->AddPreload(url, alias_urls, GURL()));
    295   EXPECT_FALSE(prerender_manager_->AddSimplePreload(url));
    296   EXPECT_FALSE(prerender_manager_->AddSimplePreload(alias_url1));
    297   EXPECT_FALSE(prerender_manager_->AddSimplePreload(alias_url2));
    298   ASSERT_EQ(pc, prerender_manager_->GetEntry(url));
    299 
    300   pc->set_final_status(FINAL_STATUS_USED);
    301   delete pc;
    302 }
    303 
    304 // Ensure that we ignore prerender requests within the rate limit.
    305 TEST_F(PrerenderManagerTest, RateLimitInWindowTest) {
    306   GURL url("http://www.google.com/");
    307   DummyPrerenderContents* pc =
    308       new DummyPrerenderContents(prerender_manager_.get(), url,
    309                                  FINAL_STATUS_MANAGER_SHUTDOWN);
    310   DummyPrerenderContents* null = NULL;
    311   prerender_manager_->SetNextPrerenderContents(pc);
    312   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    313   EXPECT_EQ(null, prerender_manager_->next_pc());
    314   EXPECT_TRUE(pc->has_started());
    315 
    316   prerender_manager_->set_rate_limit_enabled(true);
    317   prerender_manager_->AdvanceTimeTicks(base::TimeDelta::FromMilliseconds(1));
    318 
    319   GURL url1("http://news.google.com/");
    320   DummyPrerenderContents* rate_limit_pc =
    321       new DummyPrerenderContents(prerender_manager_.get(), url1,
    322                                  FINAL_STATUS_MANAGER_SHUTDOWN);
    323   prerender_manager_->SetNextPrerenderContents(rate_limit_pc);
    324   EXPECT_FALSE(prerender_manager_->AddSimplePreload(url1));
    325   prerender_manager_->set_rate_limit_enabled(false);
    326 }
    327 
    328 // Ensure that we don't ignore prerender requests outside the rate limit.
    329 TEST_F(PrerenderManagerTest, RateLimitOutsideWindowTest) {
    330   GURL url("http://www.google.com/");
    331   DummyPrerenderContents* pc =
    332       new DummyPrerenderContents(prerender_manager_.get(), url,
    333                                  FINAL_STATUS_EVICTED);
    334   DummyPrerenderContents* null = NULL;
    335   prerender_manager_->SetNextPrerenderContents(pc);
    336   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    337   EXPECT_EQ(null, prerender_manager_->next_pc());
    338   EXPECT_TRUE(pc->has_started());
    339 
    340   prerender_manager_->set_rate_limit_enabled(true);
    341   prerender_manager_->AdvanceTimeTicks(base::TimeDelta::FromMilliseconds(2000));
    342 
    343   GURL url1("http://news.google.com/");
    344   DummyPrerenderContents* rate_limit_pc =
    345       new DummyPrerenderContents(prerender_manager_.get(), url1,
    346                                  FINAL_STATUS_MANAGER_SHUTDOWN);
    347   prerender_manager_->SetNextPrerenderContents(rate_limit_pc);
    348   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url1));
    349   EXPECT_EQ(null, prerender_manager_->next_pc());
    350   EXPECT_TRUE(rate_limit_pc->has_started());
    351   prerender_manager_->set_rate_limit_enabled(false);
    352 }
    353 
    354 TEST_F(PrerenderManagerTest, PendingPreloadTest) {
    355   GURL url("http://www.google.com/");
    356   DummyPrerenderContents* pc =
    357       new DummyPrerenderContents(prerender_manager_.get(),
    358                                  url,
    359                                  FINAL_STATUS_USED);
    360   prerender_manager_->SetNextPrerenderContents(pc);
    361   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    362 
    363   int child_id;
    364   int route_id;
    365   ASSERT_TRUE(pc->GetChildId(&child_id));
    366   ASSERT_TRUE(pc->GetRouteId(&route_id));
    367 
    368   GURL pending_url("http://news.google.com/");
    369 
    370   prerender_manager_->AddPendingPreload(std::make_pair(child_id, route_id),
    371                                         pending_url,
    372                                         std::vector<GURL>(),
    373                                         url);
    374 
    375   EXPECT_TRUE(prerender_manager_->IsPendingEntry(pending_url));
    376   EXPECT_TRUE(pc->has_started());
    377   ASSERT_EQ(pc, prerender_manager_->GetEntry(url));
    378   pc->set_final_status(FINAL_STATUS_USED);
    379 
    380   delete pc;
    381 }
    382 
    383 TEST_F(PrerenderManagerTest, PendingPreloadSkippedTest) {
    384   GURL url("http://www.google.com/");
    385   DummyPrerenderContents* pc =
    386       new DummyPrerenderContents(prerender_manager_.get(),
    387                                  url,
    388                                  FINAL_STATUS_TIMED_OUT);
    389   prerender_manager_->SetNextPrerenderContents(pc);
    390 
    391   int child_id;
    392   int route_id;
    393   ASSERT_TRUE(pc->GetChildId(&child_id));
    394   ASSERT_TRUE(pc->GetRouteId(&route_id));
    395 
    396   EXPECT_TRUE(prerender_manager_->AddSimplePreload(url));
    397   prerender_manager_->AdvanceTime(prerender_manager_->max_prerender_age()
    398                                   + base::TimeDelta::FromSeconds(1));
    399   // GetEntry will cull old entries which should now include pc.
    400   ASSERT_EQ(NULL, prerender_manager_->GetEntry(url));
    401 
    402   GURL pending_url("http://news.google.com/");
    403 
    404   prerender_manager_->AddPendingPreload(std::make_pair(child_id, route_id),
    405                                         pending_url,
    406                                         std::vector<GURL>(),
    407                                         url);
    408   EXPECT_FALSE(prerender_manager_->IsPendingEntry(pending_url));
    409 }
    410 
    411 // Ensure that extracting a urlencoded URL in the url= query string component
    412 // works.
    413 TEST_F(PrerenderManagerTest, ExtractURLInQueryStringTest) {
    414   GURL result;
    415   EXPECT_TRUE(PrerenderManager::MaybeGetQueryStringBasedAliasURL(
    416       GURL("http://www.google.com/url?sa=t&source=web&cd=1&ved=0CBcQFjAA&url=http%3A%2F%2Fwww.abercrombie.com%2Fwebapp%2Fwcs%2Fstores%2Fservlet%2FStoreLocator%3FcatalogId%3D%26storeId%3D10051%26langId%3D-1&rct=j&q=allinurl%3A%26&ei=KLyUTYGSEdTWiAKUmLCdCQ&usg=AFQjCNF8nJ2MpBFfr1ijO39_f22bcKyccw&sig2=2ymyGpO0unJwU1d4kdCUjQ"),
    417       &result));
    418   ASSERT_EQ(GURL("http://www.abercrombie.com/webapp/wcs/stores/servlet/StoreLocator?catalogId=&storeId=10051&langId=-1").spec(), result.spec());
    419   EXPECT_FALSE(PrerenderManager::MaybeGetQueryStringBasedAliasURL(
    420       GURL("http://www.google.com/url?sadf=test&blah=blahblahblah"), &result));
    421   EXPECT_FALSE(PrerenderManager::MaybeGetQueryStringBasedAliasURL(
    422       GURL("http://www.google.com/?url=INVALIDurlsAREsoMUCHfun.com"), &result));
    423   EXPECT_TRUE(PrerenderManager::MaybeGetQueryStringBasedAliasURL(
    424       GURL("http://www.google.com/?url=http://validURLSareGREAT.com"),
    425       &result));
    426   ASSERT_EQ(GURL("http://validURLSareGREAT.com").spec(), result.spec());
    427 }
    428 
    429 }  // namespace prerender
    430