Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / web / tests / PrerenderingTest.cpp
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 blink;
57 using blink::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()
181     {
182         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
183     }
184
185     void initialize(const char* baseURL, const char* fileName)
186     {
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);
191
192         FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), std::string(baseURL) + fileName);
193         Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
194     }
195
196     void navigateAway()
197     {
198         FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), "about:blank");
199     }
200
201     void close()
202     {
203         m_webViewHelper.webView()->mainFrame()->collectGarbage();
204         m_webViewHelper.reset();
205
206         WebCache::clear();
207     }
208
209     WebElement console()
210     {
211         WebElement console = m_webViewHelper.webView()->mainFrame()->document().getElementById("console");
212         ASSERT(console.nodeName() == "UL");
213         return console;
214     }
215
216     unsigned consoleLength()
217     {
218         return console().childNodes().length() - 1;
219     }
220
221     std::string consoleAt(unsigned i)
222     {
223         ASSERT(consoleLength() > i);
224
225         WebNode consoleListItem = console().childNodes().item(1 + i);
226         ASSERT(consoleListItem.nodeName() == "LI");
227         ASSERT(consoleListItem.hasChildNodes());
228
229         WebNode textNode = consoleListItem.firstChild();
230         ASSERT(textNode.nodeName() == "#text");
231
232         return textNode.nodeValue().utf8().data();
233     }
234
235     void executeScript(const char* code)
236     {
237         m_webViewHelper.webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(code)));
238     }
239
240     TestPrerenderingSupport* prerenderingSupport()
241     {
242         return &m_prerenderingSupport;
243     }
244
245     TestPrerendererClient* prerendererClient()
246     {
247         return &m_prerendererClient;
248     }
249
250 private:
251     TestPrerenderingSupport m_prerenderingSupport;
252     TestPrerendererClient m_prerendererClient;
253
254     FrameTestHelpers::WebViewHelper m_webViewHelper;
255 };
256
257 TEST_F(PrerenderingTest, SinglePrerender)
258 {
259     initialize("http://www.foo.com/", "prerender/single_prerender.html");
260
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());
265
266     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
267     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
268
269     webPrerender.didStartPrerender();
270     EXPECT_EQ(1u, consoleLength());
271     EXPECT_EQ("webkitprerenderstart", consoleAt(0));
272
273     webPrerender.didSendDOMContentLoadedForPrerender();
274     EXPECT_EQ(2u, consoleLength());
275     EXPECT_EQ("webkitprerenderdomcontentloaded", consoleAt(1));
276
277     webPrerender.didSendLoadForPrerender();
278     EXPECT_EQ(3u, consoleLength());
279     EXPECT_EQ("webkitprerenderload", consoleAt(2));
280
281     webPrerender.didStopPrerender();
282     EXPECT_EQ(4u, consoleLength());
283     EXPECT_EQ("webkitprerenderstop", consoleAt(3));
284 }
285
286 TEST_F(PrerenderingTest, CancelPrerender)
287 {
288     initialize("http://www.foo.com/", "prerender/single_prerender.html");
289
290     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
291     EXPECT_FALSE(webPrerender.isNull());
292
293     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
294     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
295
296     executeScript("removePrerender()");
297
298     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(webPrerender));
299     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
300 }
301
302 TEST_F(PrerenderingTest, AbandonPrerender)
303 {
304     initialize("http://www.foo.com/", "prerender/single_prerender.html");
305
306     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
307     EXPECT_FALSE(webPrerender.isNull());
308
309     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
310     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
311
312     navigateAway();
313
314     EXPECT_EQ(1u, prerenderingSupport()->abandonCount(webPrerender));
315     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
316
317     // Check that the prerender does not emit an extra cancel when garbage-collecting everything.
318     close();
319
320     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
321 }
322
323 TEST_F(PrerenderingTest, ExtraData)
324 {
325     class TestExtraData : public WebPrerender::ExtraData {
326     public:
327         explicit TestExtraData(bool* alive) : m_alive(alive)
328         {
329             *alive = true;
330         }
331
332         virtual ~TestExtraData() { *m_alive = false; }
333
334     private:
335         bool* m_alive;
336     };
337
338     bool alive = false;
339     {
340         prerendererClient()->setExtraDataForNextPrerender(new TestExtraData(&alive));
341         initialize("http://www.foo.com/", "prerender/single_prerender.html");
342         EXPECT_TRUE(alive);
343
344         WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
345
346         executeScript("removePrerender()");
347         close();
348         prerenderingSupport()->clear();
349     }
350     EXPECT_FALSE(alive);
351 }
352
353 TEST_F(PrerenderingTest, TwoPrerenders)
354 {
355     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
356
357     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
358     EXPECT_FALSE(firstPrerender.isNull());
359     EXPECT_EQ(toWebURL("http://first-prerender.com/"), firstPrerender.url());
360
361     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
362     EXPECT_FALSE(firstPrerender.isNull());
363     EXPECT_EQ(toWebURL("http://second-prerender.com/"), secondPrerender.url());
364
365     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
366     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
367     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
368
369     firstPrerender.didStartPrerender();
370     EXPECT_EQ(1u, consoleLength());
371     EXPECT_EQ("first_webkitprerenderstart", consoleAt(0));
372
373     secondPrerender.didStartPrerender();
374     EXPECT_EQ(2u, consoleLength());
375     EXPECT_EQ("second_webkitprerenderstart", consoleAt(1));
376 }
377
378 TEST_F(PrerenderingTest, TwoPrerendersRemovingFirstThenNavigating)
379 {
380     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
381
382     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
383     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
384
385     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
386     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
387     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
388
389     executeScript("removeFirstPrerender()");
390
391     EXPECT_EQ(1u, prerenderingSupport()->cancelCount(firstPrerender));
392     EXPECT_EQ(3u, prerenderingSupport()->totalCount());
393
394     navigateAway();
395
396     EXPECT_EQ(1u, prerenderingSupport()->abandonCount(secondPrerender));
397     EXPECT_EQ(4u, prerenderingSupport()->totalCount());
398 }
399
400 TEST_F(PrerenderingTest, TwoPrerendersAddingThird)
401 {
402     initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
403
404     WebPrerender firstPrerender = prerendererClient()->releaseWebPrerender();
405     WebPrerender secondPrerender = prerendererClient()->releaseWebPrerender();
406
407     EXPECT_EQ(1u, prerenderingSupport()->addCount(firstPrerender));
408     EXPECT_EQ(1u, prerenderingSupport()->addCount(secondPrerender));
409     EXPECT_EQ(2u, prerenderingSupport()->totalCount());
410
411     executeScript("addThirdPrerender()");
412
413     WebPrerender thirdPrerender = prerendererClient()->releaseWebPrerender();
414     EXPECT_EQ(1u, prerenderingSupport()->addCount(thirdPrerender));
415     EXPECT_EQ(3u, prerenderingSupport()->totalCount());
416 }
417
418 TEST_F(PrerenderingTest, ShortLivedClient)
419 {
420     initialize("http://www.foo.com/", "prerender/single_prerender.html");
421
422     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
423     EXPECT_FALSE(webPrerender.isNull());
424
425     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
426     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
427
428     navigateAway();
429     close();
430
431     // This test passes if this next line doesn't crash.
432     webPrerender.didStartPrerender();
433 }
434
435 TEST_F(PrerenderingTest, FastRemoveElement)
436 {
437     initialize("http://www.foo.com/", "prerender/single_prerender.html");
438
439     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
440     EXPECT_FALSE(webPrerender.isNull());
441
442     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
443     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
444
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();
449
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());
452 }
453
454 TEST_F(PrerenderingTest, MutateTarget)
455 {
456     initialize("http://www.foo.com/", "prerender/single_prerender.html");
457
458     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
459     EXPECT_FALSE(webPrerender.isNull());
460     EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender.url());
461
462     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
463     EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender));
464     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
465
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));
469
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());
475 }
476
477 TEST_F(PrerenderingTest, MutateRel)
478 {
479     initialize("http://www.foo.com/", "prerender/single_prerender.html");
480
481     WebPrerender webPrerender = prerendererClient()->releaseWebPrerender();
482     EXPECT_FALSE(webPrerender.isNull());
483     EXPECT_EQ(toWebURL("http://prerender.com/"), webPrerender.url());
484
485     EXPECT_EQ(1u, prerenderingSupport()->addCount(webPrerender));
486     EXPECT_EQ(0u, prerenderingSupport()->cancelCount(webPrerender));
487     EXPECT_EQ(1u, prerenderingSupport()->totalCount());
488
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());
493 }
494
495 TEST_F(PrerenderingTest, RelNext)
496 {
497     initialize("http://www.foo.com/", "prerender/rel_next_prerender.html");
498
499     WebPrerender relNextOnly = prerendererClient()->releaseWebPrerender();
500     EXPECT_EQ(toWebURL("http://rel-next-only.com/"), relNextOnly.url());
501     EXPECT_EQ(PrerenderRelTypeNext, relNextOnly.relTypes());
502
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());
506 }
507
508 } // namespace