Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / tests / PrerenderingTest.cpp
blob4c80bfeff6f79079e92bde28d2a0ebde616f2f5d
1 /*
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
6 * met:
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.
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.
31 #include "config.h"
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"
52 #include <functional>
53 #include <gtest/gtest.h>
54 #include <list>
56 using namespace blink;
57 using blink::URLTestHelpers::toKURL;
59 namespace {
61 WebURL toWebURL(const char* url)
63 return WebURL(toKURL(url));
66 class TestPrerendererClient : public WebPrerendererClient {
67 public:
68 TestPrerendererClient() { }
69 virtual ~TestPrerendererClient() { }
71 void setExtraDataForNextPrerender(WebPrerender::ExtraData* extraData)
73 ASSERT(!m_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();
82 return retval;
85 bool empty() const
87 return m_webPrerenders.empty();
90 void clear()
92 m_webPrerenders.clear();
95 private:
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 {
110 public:
111 TestPrerenderingSupport()
113 initialize(this);
116 ~TestPrerenderingSupport() override
118 shutdown();
121 void clear()
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));
148 private:
149 class WebPrerenderEqual : public std::binary_function<WebPrerender, WebPrerender, bool> {
150 public:
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 {
179 public:
180 ~PrerenderingTest()
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);
195 void navigateAway()
197 FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), "about:blank");
200 void close()
202 m_webViewHelper.webView()->mainFrame()->collectGarbage();
203 m_webViewHelper.reset();
205 WebCache::clear();
208 WebElement console()
210 WebElement console = m_webViewHelper.webView()->mainFrame()->document().getElementById("console");
211 ASSERT(console.hasHTMLTagName("UL"));
212 return console;
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;
250 private:
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());
312 navigateAway();
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.
318 close();
320 EXPECT_EQ(2u, prerenderingSupport()->totalCount());
323 TEST_F(PrerenderingTest, ExtraData)
325 class TestExtraData : public WebPrerender::ExtraData {
326 public:
327 explicit TestExtraData(bool* alive) : m_alive(alive)
329 *alive = true;
332 ~TestExtraData() override { *m_alive = false; }
334 private:
335 bool* m_alive;
338 bool alive = false;
340 prerendererClient()->setExtraDataForNextPrerender(new TestExtraData(&alive));
341 initialize("http://www.foo.com/", "prerender/single_prerender.html");
342 EXPECT_TRUE(alive);
344 WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
346 executeScript("removePrerender()");
347 close();
348 prerenderingSupport()->clear();
350 EXPECT_FALSE(alive);
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());
394 navigateAway();
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());
428 navigateAway();
429 close();
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());
508 } // namespace