2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "platform/testing/URLTestHelpers.h"
34 #include "public/web/WebCache.h"
35 #include "public/web/WebDocument.h"
36 #include "public/web/WebElement.h"
37 #include "public/web/WebFrame.h"
38 #include "public/web/WebNode.h"
39 #include "public/web/WebNodeList.h"
40 #include "public/web/WebPrerendererClient.h"
41 #include "public/web/WebScriptSource.h"
42 #include "public/web/WebView.h"
43 #include "public/web/WebViewClient.h"
44 #include "web/tests/FrameTestHelpers.h"
46 #include "public/platform/Platform.h"
47 #include "public/platform/WebPrerender.h"
48 #include "public/platform/WebPrerenderingSupport.h"
49 #include "public/platform/WebString.h"
50 #include "public/platform/WebUnitTestSupport.h"
51 #include "wtf/OwnPtr.h"
53 #include <gtest/gtest.h>
56 using namespace blink
;
57 using blink::URLTestHelpers::toKURL
;
61 WebURL
toWebURL(const char* url
)
63 return WebURL(toKURL(url
));
66 class TestPrerendererClient
: public WebPrerendererClient
{
68 TestPrerendererClient() { }
69 virtual ~TestPrerendererClient() { }
71 void setExtraDataForNextPrerender(WebPrerender::ExtraData
* extraData
)
74 m_extraData
= adoptPtr(extraData
);
77 WebPrerender
releaseWebPrerender()
79 ASSERT(!m_webPrerenders
.empty());
80 WebPrerender
retval(m_webPrerenders
.front());
81 m_webPrerenders
.pop_front();
87 return m_webPrerenders
.empty();
92 m_webPrerenders
.clear();
96 // From WebPrerendererClient:
97 void willAddPrerender(WebPrerender
* prerender
) override
99 prerender
->setExtraData(m_extraData
.leakPtr());
101 ASSERT(!prerender
->isNull());
102 m_webPrerenders
.push_back(*prerender
);
105 OwnPtr
<WebPrerender::ExtraData
> m_extraData
;
106 std::list
<WebPrerender
> m_webPrerenders
;
109 class TestPrerenderingSupport
: public WebPrerenderingSupport
{
111 TestPrerenderingSupport()
116 ~TestPrerenderingSupport() override
123 m_addedPrerenders
.clear();
124 m_canceledPrerenders
.clear();
125 m_abandonedPrerenders
.clear();
128 size_t totalCount() const
130 return m_addedPrerenders
.size() + m_canceledPrerenders
.size() + m_abandonedPrerenders
.size();
133 size_t addCount(const WebPrerender
& prerender
) const
135 return std::count_if(m_addedPrerenders
.begin(), m_addedPrerenders
.end(), std::bind1st(WebPrerenderEqual(), prerender
));
138 size_t cancelCount(const WebPrerender
& prerender
) const
140 return std::count_if(m_canceledPrerenders
.begin(), m_canceledPrerenders
.end(), std::bind1st(WebPrerenderEqual(), prerender
));
143 size_t abandonCount(const WebPrerender
& prerender
) const
145 return std::count_if(m_abandonedPrerenders
.begin(), m_abandonedPrerenders
.end(), std::bind1st(WebPrerenderEqual(), prerender
));
149 class WebPrerenderEqual
: public std::binary_function
<WebPrerender
, WebPrerender
, bool> {
151 bool operator()(const WebPrerender
& first
, const WebPrerender
& second
) const
153 return first
.toPrerender() == second
.toPrerender();
157 // From WebPrerenderingSupport:
158 void add(const WebPrerender
& prerender
) override
160 m_addedPrerenders
.push_back(prerender
);
163 void cancel(const WebPrerender
& prerender
) override
165 m_canceledPrerenders
.push_back(prerender
);
168 void abandon(const WebPrerender
& prerender
) override
170 m_abandonedPrerenders
.push_back(prerender
);
173 std::vector
<WebPrerender
> m_addedPrerenders
;
174 std::vector
<WebPrerender
> m_canceledPrerenders
;
175 std::vector
<WebPrerender
> m_abandonedPrerenders
;
178 class PrerenderingTest
: public testing::Test
{
182 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
185 void initialize(const char* baseURL
, const char* fileName
)
187 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL
), WebString::fromUTF8(fileName
));
188 const bool RunJavascript
= true;
189 m_webViewHelper
.initialize(RunJavascript
);
190 m_webViewHelper
.webView()->setPrerendererClient(&m_prerendererClient
);
192 FrameTestHelpers::loadFrame(m_webViewHelper
.webView()->mainFrame(), std::string(baseURL
) + fileName
);
197 FrameTestHelpers::loadFrame(m_webViewHelper
.webView()->mainFrame(), "about:blank");
202 m_webViewHelper
.webView()->mainFrame()->collectGarbage();
203 m_webViewHelper
.reset();
210 WebElement console
= m_webViewHelper
.webView()->mainFrame()->document().getElementById("console");
211 ASSERT(console
.hasHTMLTagName("UL"));
215 unsigned consoleLength()
217 return console().childNodes().length() - 1;
220 std::string
consoleAt(unsigned i
)
222 ASSERT(consoleLength() > i
);
224 WebNode consoleListItem
= console().childNodes().item(1 + i
);
225 ASSERT(consoleListItem
.isElementNode());
226 ASSERT(consoleListItem
.to
<WebElement
>().hasHTMLTagName("LI"));
227 ASSERT(consoleListItem
.hasChildNodes());
229 WebNode textNode
= consoleListItem
.firstChild();
230 ASSERT(textNode
.isTextNode());
232 return textNode
.nodeValue().utf8().data();
235 void executeScript(const char* code
)
237 m_webViewHelper
.webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(code
)));
240 TestPrerenderingSupport
* prerenderingSupport()
242 return &m_prerenderingSupport
;
245 TestPrerendererClient
* prerendererClient()
247 return &m_prerendererClient
;
251 TestPrerenderingSupport m_prerenderingSupport
;
252 TestPrerendererClient m_prerendererClient
;
254 FrameTestHelpers::WebViewHelper m_webViewHelper
;
257 TEST_F(PrerenderingTest
, SinglePrerender
)
259 initialize("http://www.foo.com/", "prerender/single_prerender.html");
261 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
262 EXPECT_FALSE(webPrerender
.isNull());
263 EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender
.url());
264 EXPECT_EQ(PrerenderRelTypePrerender
, webPrerender
.relTypes());
266 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
267 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
269 webPrerender
.didStartPrerender();
270 EXPECT_EQ(1u, consoleLength());
271 EXPECT_EQ("webkitprerenderstart", consoleAt(0));
273 webPrerender
.didSendDOMContentLoadedForPrerender();
274 EXPECT_EQ(2u, consoleLength());
275 EXPECT_EQ("webkitprerenderdomcontentloaded", consoleAt(1));
277 webPrerender
.didSendLoadForPrerender();
278 EXPECT_EQ(3u, consoleLength());
279 EXPECT_EQ("webkitprerenderload", consoleAt(2));
281 webPrerender
.didStopPrerender();
282 EXPECT_EQ(4u, consoleLength());
283 EXPECT_EQ("webkitprerenderstop", consoleAt(3));
286 TEST_F(PrerenderingTest
, CancelPrerender
)
288 initialize("http://www.foo.com/", "prerender/single_prerender.html");
290 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
291 EXPECT_FALSE(webPrerender
.isNull());
293 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
294 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
296 executeScript("removePrerender()");
298 EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender
));
299 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
302 TEST_F(PrerenderingTest
, AbandonPrerender
)
304 initialize("http://www.foo.com/", "prerender/single_prerender.html");
306 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
307 EXPECT_FALSE(webPrerender
.isNull());
309 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
310 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
314 EXPECT_EQ(1u, prerenderingSupport()->abandonCount(webPrerender
));
315 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
317 // Check that the prerender does not emit an extra cancel when garbage-collecting everything.
320 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
323 TEST_F(PrerenderingTest
, ExtraData
)
325 class TestExtraData
: public WebPrerender::ExtraData
{
327 explicit TestExtraData(bool* alive
) : m_alive(alive
)
332 ~TestExtraData() override
{ *m_alive
= false; }
340 prerendererClient()->setExtraDataForNextPrerender(new TestExtraData(&alive
));
341 initialize("http://www.foo.com/", "prerender/single_prerender.html");
344 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
346 executeScript("removePrerender()");
348 prerenderingSupport()->clear();
353 TEST_F(PrerenderingTest
, TwoPrerenders
)
355 initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
357 WebPrerender firstPrerender
= prerendererClient()->releaseWebPrerender();
358 EXPECT_FALSE(firstPrerender
.isNull());
359 EXPECT_EQ(toWebURL("http://first-prerender.com/"), firstPrerender
.url());
361 WebPrerender secondPrerender
= prerendererClient()->releaseWebPrerender();
362 EXPECT_FALSE(firstPrerender
.isNull());
363 EXPECT_EQ(toWebURL("http://second-prerender.com/"), secondPrerender
.url());
365 EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender
));
366 EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender
));
367 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
369 firstPrerender
.didStartPrerender();
370 EXPECT_EQ(1u, consoleLength());
371 EXPECT_EQ("first_webkitprerenderstart", consoleAt(0));
373 secondPrerender
.didStartPrerender();
374 EXPECT_EQ(2u, consoleLength());
375 EXPECT_EQ("second_webkitprerenderstart", consoleAt(1));
378 TEST_F(PrerenderingTest
, TwoPrerendersRemovingFirstThenNavigating
)
380 initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
382 WebPrerender firstPrerender
= prerendererClient()->releaseWebPrerender();
383 WebPrerender secondPrerender
= prerendererClient()->releaseWebPrerender();
385 EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender
));
386 EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender
));
387 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
389 executeScript("removeFirstPrerender()");
391 EXPECT_EQ(1u, prerenderingSupport()->cancelCount(firstPrerender
));
392 EXPECT_EQ(3u, prerenderingSupport()->totalCount());
396 EXPECT_EQ(1u, prerenderingSupport()->abandonCount(secondPrerender
));
397 EXPECT_EQ(4u, prerenderingSupport()->totalCount());
400 TEST_F(PrerenderingTest
, TwoPrerendersAddingThird
)
402 initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
404 WebPrerender firstPrerender
= prerendererClient()->releaseWebPrerender();
405 WebPrerender secondPrerender
= prerendererClient()->releaseWebPrerender();
407 EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender
));
408 EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender
));
409 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
411 executeScript("addThirdPrerender()");
413 WebPrerender thirdPrerender
= prerendererClient()->releaseWebPrerender();
414 EXPECT_EQ(1u, prerenderingSupport()->addCount(thirdPrerender
));
415 EXPECT_EQ(3u, prerenderingSupport()->totalCount());
418 TEST_F(PrerenderingTest
, ShortLivedClient
)
420 initialize("http://www.foo.com/", "prerender/single_prerender.html");
422 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
423 EXPECT_FALSE(webPrerender
.isNull());
425 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
426 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
431 // This test passes if this next line doesn't crash.
432 webPrerender
.didStartPrerender();
435 TEST_F(PrerenderingTest
, FastRemoveElement
)
437 initialize("http://www.foo.com/", "prerender/single_prerender.html");
439 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
440 EXPECT_FALSE(webPrerender
.isNull());
442 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
443 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
445 // Race removing & starting the prerender against each other, as if the element was removed very quickly.
446 executeScript("removePrerender()");
447 EXPECT_FALSE(webPrerender
.isNull());
448 webPrerender
.didStartPrerender();
450 // The page should be totally disconnected from the Prerender at this point, so the console should not have updated.
451 EXPECT_EQ(0u, consoleLength());
454 TEST_F(PrerenderingTest
, MutateTarget
)
456 initialize("http://www.foo.com/", "prerender/single_prerender.html");
458 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
459 EXPECT_FALSE(webPrerender
.isNull());
460 EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender
.url());
462 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
463 EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender
));
464 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
466 // Change the href of this prerender, make sure this is treated as a remove and add.
467 executeScript("mutateTarget()");
468 EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender
));
470 WebPrerender mutatedPrerender
= prerendererClient()->releaseWebPrerender();
471 EXPECT_EQ(toWebURL("http://mutated.com/"), mutatedPrerender
.url());
472 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
473 EXPECT_EQ(1u, prerenderingSupport()->addCount(mutatedPrerender
));
474 EXPECT_EQ(3u, prerenderingSupport()->totalCount());
477 TEST_F(PrerenderingTest
, MutateRel
)
479 initialize("http://www.foo.com/", "prerender/single_prerender.html");
481 WebPrerender webPrerender
= prerendererClient()->releaseWebPrerender();
482 EXPECT_FALSE(webPrerender
.isNull());
483 EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender
.url());
485 EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender
));
486 EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender
));
487 EXPECT_EQ(1u, prerenderingSupport()->totalCount());
489 // Change the rel of this prerender, make sure this is treated as a remove.
490 executeScript("mutateRel()");
491 EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender
));
492 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
495 TEST_F(PrerenderingTest
, RelNext
)
497 initialize("http://www.foo.com/", "prerender/rel_next_prerender.html");
499 WebPrerender relNextOnly
= prerendererClient()->releaseWebPrerender();
500 EXPECT_EQ(toWebURL("http://rel-next-only.com/"), relNextOnly
.url());
501 EXPECT_EQ(PrerenderRelTypeNext
, relNextOnly
.relTypes());
503 WebPrerender relNextAndPrerender
= prerendererClient()->releaseWebPrerender();
504 EXPECT_EQ(toWebURL("http://rel-next-and-prerender.com/"), relNextAndPrerender
.url());
505 EXPECT_EQ(static_cast<unsigned>(PrerenderRelTypeNext
| PrerenderRelTypePrerender
), relNextAndPrerender
.relTypes());