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