Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include "FrameTestHelpers.h"
     34 #include "URLTestHelpers.h"
     35 #include "WebCache.h"
     36 #include "WebDocument.h"
     37 #include "WebElement.h"
     38 #include "WebFrame.h"
     39 #include "WebNode.h"
     40 #include "WebNodeList.h"
     41 #include "WebPrerendererClient.h"
     42 #include "WebScriptSource.h"
     43 #include "WebView.h"
     44 #include "WebViewClient.h"
     45 
     46 #include <functional>
     47 #include <gtest/gtest.h>
     48 #include <list>
     49 #include "public/platform/Platform.h"
     50 #include "public/platform/WebPrerender.h"
     51 #include "public/platform/WebPrerenderingSupport.h"
     52 #include "public/platform/WebString.h"
     53 #include "public/platform/WebUnitTestSupport.h"
     54 #include "wtf/OwnPtr.h"
     55 
     56 using namespace WebKit;
     57 using WebKit::URLTestHelpers::toKURL;
     58 
     59 namespace {
     60 
     61 WebURL toWebURL(const char* url)
     62 {
     63     return WebURL(toKURL(url));
     64 }
     65 
     66 class TestPrerendererClient : public WebPrerendererClient {
     67 public:
     68     TestPrerendererClient() { }
     69     virtual ~TestPrerendererClient() { }
     70 
     71     void setExtraDataForNextPrerender(WebPrerender::ExtraData* extraData)
     72     {
     73         ASSERT(!m_extraData);
     74         m_extraData = adoptPtr(extraData);
     75     }
     76 
     77     WebPrerender releaseWebPrerender()
     78     {
     79         ASSERT(!m_webPrerenders.empty());
     80         WebPrerender retval(m_webPrerenders.front());
     81         m_webPrerenders.pop_front();
     82         return retval;
     83     }
     84 
     85     bool empty() const
     86     {
     87         return m_webPrerenders.empty();
     88     }
     89 
     90     void clear()
     91     {
     92         m_webPrerenders.clear();
     93     }
     94 
     95 private:
     96     // From WebPrerendererClient:
     97     virtual void willAddPrerender(WebPrerender* prerender) OVERRIDE
     98     {
     99         prerender->setExtraData(m_extraData.leakPtr());
    100 
    101         ASSERT(!prerender->isNull());
    102         m_webPrerenders.push_back(*prerender);
    103     }
    104 
    105     OwnPtr<WebPrerender::ExtraData> m_extraData;
    106     std::list<WebPrerender> m_webPrerenders;
    107 };
    108 
    109 class TestPrerenderingSupport : public WebPrerenderingSupport {
    110 public:
    111     TestPrerenderingSupport()
    112     {
    113         initialize(this);
    114     }
    115 
    116     virtual ~TestPrerenderingSupport()
    117     {
    118         shutdown();
    119     }
    120 
    121     void clear()
    122     {
    123         m_addedPrerenders.clear();
    124         m_canceledPrerenders.clear();
    125         m_abandonedPrerenders.clear();
    126     }
    127 
    128     size_t totalCount() const
    129     {
    130         return m_addedPrerenders.size() + m_canceledPrerenders.size() + m_abandonedPrerenders.size();
    131     }
    132 
    133     size_t addCount(const WebPrerender& prerender) const
    134     {
    135         return std::count_if(m_addedPrerenders.begin(), m_addedPrerenders.end(), std::bind1st(WebPrerenderEqual(), prerender));
    136     }
    137 
    138     size_t cancelCount(const WebPrerender& prerender) const
    139     {
    140         return std::count_if(m_canceledPrerenders.begin(), m_canceledPrerenders.end(), std::bind1st(WebPrerenderEqual(), prerender));
    141     }
    142 
    143     size_t abandonCount(const WebPrerender& prerender) const
    144     {
    145         return std::count_if(m_abandonedPrerenders.begin(), m_abandonedPrerenders.end(), std::bind1st(WebPrerenderEqual(), prerender));
    146     }
    147 
    148 private:
    149     class WebPrerenderEqual : public std::binary_function<WebPrerender, WebPrerender, bool> {
    150     public:
    151         bool operator()(const WebPrerender& first, const WebPrerender& second) const
    152         {
    153             return first.toPrerender() == second.toPrerender();
    154         }
    155     };
    156 
    157     // From WebPrerenderingSupport:
    158     virtual void add(const WebPrerender& prerender) OVERRIDE
    159     {
    160         m_addedPrerenders.push_back(prerender);
    161     }
    162 
    163     virtual void cancel(const WebPrerender& prerender) OVERRIDE
    164     {
    165         m_canceledPrerenders.push_back(prerender);
    166     }
    167 
    168     virtual void abandon(const WebPrerender& prerender) OVERRIDE
    169     {
    170         m_abandonedPrerenders.push_back(prerender);
    171     }
    172 
    173     std::vector<WebPrerender> m_addedPrerenders;
    174     std::vector<WebPrerender> m_canceledPrerenders;
    175     std::vector<WebPrerender> m_abandonedPrerenders;
    176 };
    177 
    178 class PrerenderingTest : public testing::Test {
    179 public:
    180     PrerenderingTest() : m_webView(0)
    181     {
    182     }
    183 
    184     ~PrerenderingTest()
    185     {
    186         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
    187         if (m_webView)
    188             close();
    189     }
    190 
    191     void initialize(const char* baseURL, const char* fileName)
    192     {
    193         ASSERT(!m_webView);
    194         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL), WebString::fromUTF8(fileName));
    195         const bool RunJavascript = true;
    196         m_webView = FrameTestHelpers::createWebView(RunJavascript);
    197         m_webView->setPrerendererClient(&m_prerendererClient);
    198 
    199         FrameTestHelpers::loadFrame(m_webView->mainFrame(), std::string(baseURL) + fileName);
    200         Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
    201     }
    202 
    203     void navigateAway()
    204     {
    205         FrameTestHelpers::loadFrame(m_webView->mainFrame(), "about:blank");
    206     }
    207 
    208     void close()
    209     {
    210         ASSERT(m_webView);
    211 
    212         m_webView->mainFrame()->collectGarbage();
    213 
    214         m_webView->close();
    215         m_webView = 0;
    216 
    217         WebCache::clear();
    218     }
    219 
    220     WebElement console()
    221     {
    222         WebElement console = m_webView->mainFrame()->document().getElementById("console");
    223         ASSERT(console.nodeName() == "UL");
    224         return console;
    225     }
    226 
    227     unsigned consoleLength()
    228     {
    229         return console().childNodes().length() - 1;
    230     }
    231 
    232     std::string consoleAt(unsigned i)
    233     {
    234         ASSERT(consoleLength() > i);
    235 
    236         WebNode consoleListItem = console().childNodes().item(1 + i);
    237         ASSERT(consoleListItem.nodeName() == "LI");
    238         ASSERT(consoleListItem.hasChildNodes());
    239 
    240         WebNode textNode = consoleListItem.firstChild();
    241         ASSERT(textNode.nodeName() == "#text");
    242 
    243         return textNode.nodeValue().utf8().data();
    244     }
    245 
    246     void executeScript(const char* code)
    247     {
    248         m_webView->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(code)));
    249     }
    250 
    251     TestPrerenderingSupport* prerenderingSupport()
    252     {
    253         return &m_prerenderingSupport;
    254     }
    255 
    256     TestPrerendererClient* prerendererClient()
    257     {
    258         return &m_prerendererClient;
    259     }
    260 
    261 private:
    262     TestPrerenderingSupport m_prerenderingSupport;
    263     TestPrerendererClient m_prerendererClient;
    264 
    265     WebView* m_webView;
    266 };
    267 
    268 TEST_F(PrerenderingTest, SinglePrerender)
    269 {
    270     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    271 
    272     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    273     EXPECT_FALSE(webPrerender.isNull());
    274     EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender.url());
    275 
    276     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    277     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    278 
    279     webPrerender.didStartPrerender();
    280     EXPECT_EQ(1u, consoleLength());
    281     EXPECT_EQ("webkitprerenderstart", consoleAt(0));
    282 
    283     webPrerender.didSendDOMContentLoadedForPrerender();
    284     EXPECT_EQ(2u, consoleLength());
    285     EXPECT_EQ("webkitprerenderdomcontentloaded", consoleAt(1));
    286 
    287     webPrerender.didSendLoadForPrerender();
    288     EXPECT_EQ(3u, consoleLength());
    289     EXPECT_EQ("webkitprerenderload", consoleAt(2));
    290 
    291     webPrerender.didStopPrerender();
    292     EXPECT_EQ(4u, consoleLength());
    293     EXPECT_EQ("webkitprerenderstop", consoleAt(3));
    294 }
    295 
    296 TEST_F(PrerenderingTest, CancelPrerender)
    297 {
    298     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    299 
    300     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    301     EXPECT_FALSE(webPrerender.isNull());
    302 
    303     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    304     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    305 
    306     executeScript("removePrerender()");
    307 
    308     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender));
    309     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    310 }
    311 
    312 TEST_F(PrerenderingTest, AbandonPrerender)
    313 {
    314     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    315 
    316     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    317     EXPECT_FALSE(webPrerender.isNull());
    318 
    319     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    320     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    321 
    322     navigateAway();
    323 
    324     EXPECT_EQ(1u, prerenderingSupport()->abandonCount(webPrerender));
    325     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    326 }
    327 
    328 TEST_F(PrerenderingTest, ExtraData)
    329 {
    330     class TestExtraData : public WebPrerender::ExtraData {
    331     public:
    332         explicit TestExtraData(bool* alive) : m_alive(alive)
    333         {
    334             *alive = true;
    335         }
    336 
    337         virtual ~TestExtraData() { *m_alive = false; }
    338 
    339     private:
    340         bool* m_alive;
    341     };
    342 
    343     bool alive = false;
    344     {
    345         prerendererClient()->setExtraDataForNextPrerender(new TestExtraData(&alive));
    346         initialize("http://www.foo.com/", "prerender/single_prerender.html");
    347         EXPECT_TRUE(alive);
    348 
    349         WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    350 
    351         executeScript("removePrerender()");
    352         close();
    353         prerenderingSupport()->clear();
    354     }
    355     EXPECT_FALSE(alive);
    356 }
    357 
    358 TEST_F(PrerenderingTest, TwoPrerenders)
    359 {
    360     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
    361 
    362     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
    363     EXPECT_FALSE(firstPrerender.isNull());
    364     EXPECT_EQ(toWebURL("http://first-prerender.com/"), firstPrerender.url());
    365 
    366     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
    367     EXPECT_FALSE(firstPrerender.isNull());
    368     EXPECT_EQ(toWebURL("http://second-prerender.com/"), secondPrerender.url());
    369 
    370     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
    371     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
    372     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    373 
    374     firstPrerender.didStartPrerender();
    375     EXPECT_EQ(1u, consoleLength());
    376     EXPECT_EQ("first_webkitprerenderstart", consoleAt(0));
    377 
    378     secondPrerender.didStartPrerender();
    379     EXPECT_EQ(2u, consoleLength());
    380     EXPECT_EQ("second_webkitprerenderstart", consoleAt(1));
    381 }
    382 
    383 TEST_F(PrerenderingTest, TwoPrerendersRemovingFirstThenNavigating)
    384 {
    385     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
    386 
    387     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
    388     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
    389 
    390     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
    391     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
    392     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    393 
    394     executeScript("removeFirstPrerender()");
    395 
    396     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(firstPrerender));
    397     EXPECT_EQ(3u, prerenderingSupport()->totalCount());
    398 
    399     navigateAway();
    400 
    401     EXPECT_EQ(1u, prerenderingSupport()->abandonCount(secondPrerender));
    402 
    403     // FIXME: After we fix prerenders such that they don't send redundant events, assert that totalCount() == 4u.
    404 }
    405 
    406 TEST_F(PrerenderingTest, TwoPrerendersAddingThird)
    407 {
    408     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
    409 
    410     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
    411     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
    412 
    413     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
    414     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
    415     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    416 
    417     executeScript("addThirdPrerender()");
    418 
    419     WebPrerender thirdPrerender = prerendererClient()->releaseWebPrerender();
    420     EXPECT_EQ(1u, prerenderingSupport()->addCount(thirdPrerender));
    421     EXPECT_EQ(3u, prerenderingSupport()->totalCount());
    422 }
    423 
    424 TEST_F(PrerenderingTest, ShortLivedClient)
    425 {
    426     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    427 
    428     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    429     EXPECT_FALSE(webPrerender.isNull());
    430 
    431     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    432     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    433 
    434     navigateAway();
    435     close();
    436 
    437     // This test passes if this next line doesn't crash.
    438     webPrerender.didStartPrerender();
    439 }
    440 
    441 TEST_F(PrerenderingTest, FastRemoveElement)
    442 {
    443     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    444 
    445     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    446     EXPECT_FALSE(webPrerender.isNull());
    447 
    448     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    449     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    450 
    451     // Race removing & starting the prerender against each other, as if the element was removed very quickly.
    452     executeScript("removePrerender()");
    453     EXPECT_FALSE(webPrerender.isNull());
    454     webPrerender.didStartPrerender();
    455 
    456     // The page should be totally disconnected from the Prerender at this point, so the console should not have updated.
    457     EXPECT_EQ(0u, consoleLength());
    458 }
    459 
    460 TEST_F(PrerenderingTest, MutateTarget)
    461 {
    462     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    463 
    464     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    465     EXPECT_FALSE(webPrerender.isNull());
    466     EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender.url());
    467 
    468     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    469     EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender));
    470     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    471 
    472     // Change the href of this prerender, make sure this is treated as a remove and add.
    473     executeScript("mutateTarget()");
    474     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender));
    475 
    476     WebPrerender mutatedPrerender = prerendererClient()->releaseWebPrerender();
    477     EXPECT_EQ(toWebURL("http://mutated.com/"), mutatedPrerender.url());
    478     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    479     EXPECT_EQ(1u, prerenderingSupport()->addCount(mutatedPrerender));
    480     EXPECT_EQ(3u, prerenderingSupport()->totalCount());
    481 }
    482 
    483 TEST_F(PrerenderingTest, MutateRel)
    484 {
    485     initialize("http://www.foo.com/", "prerender/single_prerender.html");
    486 
    487     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
    488     EXPECT_FALSE(webPrerender.isNull());
    489     EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender.url());
    490 
    491     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
    492     EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender));
    493     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
    494 
    495     // Change the rel of this prerender, make sure this is treated as a remove.
    496     executeScript("mutateRel()");
    497     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender));
    498     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
    499 }
    500 
    501 } // namespace
    502