93aef9b29ed91852762a89f53d94dd9c5e798b75
[platform/framework/web/crosswalk.git] / src / xwalk / test / android / core / javatests / src / org / xwalk / core / xwview / test / ShouldInterceptLoadRequestTest.java
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2014 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 package org.xwalk.core.xwview.test;
7
8 import android.test.suitebuilder.annotation.SmallTest;
9 import android.util.Pair;
10 import android.webkit.WebResourceResponse;
11
12 import java.io.ByteArrayInputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CountDownLatch;
18
19 import org.chromium.base.test.util.DisabledTest;
20 import org.chromium.base.test.util.Feature;
21 import org.chromium.base.test.util.TestFileUtil;
22 import org.chromium.content.browser.test.util.CallbackHelper;
23 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
24 import org.chromium.net.test.util.TestWebServer;
25
26 import org.xwalk.core.XWalkView;
27 import org.xwalk.core.xwview.test.TestContentProvider;
28 import org.xwalk.core.xwview.test.util.CommonResources;
29
30 /**
31  * Test case for XWalkResourceClient.shouldInterceptRequest callback
32  *
33  * Note the major part of this file is migrated from android_webview/.
34  */
35 public class ShouldInterceptLoadRequestTest extends XWalkViewTestBase {
36
37     /**
38      * Customized XWalkResourceClient implementation for shouldInterceptRequest
39      */
40     private class TestXWalkResourceClient1 extends XWalkViewTestBase.TestXWalkResourceClient {
41         @Override
42         public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
43             return mTestHelperBridge.shouldInterceptLoadRequest(url);
44         }
45
46     }
47
48     private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
49         List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
50         headers.add(Pair.create("Content-Type", "text/html"));
51         headers.add(Pair.create("Cache-Control", "no-store"));
52         return webServer.setResponse(httpPath, html, headers);
53     }
54
55     private String addAboutPageToTestServer(TestWebServer webServer) {
56         return addPageToTestServer(webServer, "/" + CommonResources.ABOUT_FILENAME,
57                 CommonResources.ABOUT_HTML);
58     }
59
60     private WebResourceResponse stringToWebResourceResponse(String input) throws Throwable {
61         final String mimeType = "text/html";
62         final String encoding = "UTF-8";
63
64         return new WebResourceResponse(
65                 mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding)));
66     }
67
68     private TestWebServer mWebServer;
69     private TestXWalkResourceClient1 mTestXWalkResourceClient;
70     private TestHelperBridge.ShouldInterceptLoadRequestHelper mShouldInterceptLoadRequestHelper;
71     private TestHelperBridge.OnLoadStartedHelper mOnLoadStartedHelper;
72
73     @Override
74     protected void setUp() throws Exception {
75         super.setUp();
76
77         setXWalkClient(new XWalkViewTestBase.TestXWalkClient());
78         getInstrumentation().runOnMainSync(new Runnable() {
79             @Override
80             public void run() {
81                 mTestXWalkResourceClient = new TestXWalkResourceClient1();
82                 getXWalkView().setResourceClient(mTestXWalkResourceClient);
83                 mShouldInterceptLoadRequestHelper = mTestHelperBridge.getShouldInterceptLoadRequestHelper();
84                 mOnLoadStartedHelper = mTestHelperBridge.getOnLoadStartedHelper();
85             }
86         });
87
88         mWebServer = new TestWebServer(false);
89     }
90
91     @Override
92     protected void tearDown() throws Exception {
93         mWebServer.shutdown();
94         super.tearDown();
95     }
96
97     @SmallTest
98     @Feature({"ShouldInterceptLoadRequest"})
99     public void testCalledWithCorrectUrl() throws Throwable {
100         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
101
102         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
103         int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
104
105         loadUrlAsync(aboutPageUrl);
106
107         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
108         assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
109         assertEquals(aboutPageUrl,
110                 mShouldInterceptLoadRequestHelper.getUrls().get(0));
111
112         mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
113         assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread());
114     }
115
116     @SmallTest
117     @Feature({"ShouldInterceptLoadRequest"})
118     public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
119         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
120         int callCount = mOnLoadStartedHelper.getCallCount();
121
122         loadUrlAsync(aboutPageUrl);
123
124         mOnLoadStartedHelper.waitForCallback(callCount);
125         assertEquals(aboutPageUrl, mOnLoadStartedHelper.getUrl());
126     }
127
128     @SmallTest
129     @Feature({"ShouldInterceptLoadRequest"})
130     public void testDoesNotCrashOnInvalidData() throws Throwable {
131         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
132
133         mShouldInterceptLoadRequestHelper.setReturnValue(
134                 new WebResourceResponse("text/html", "UTF-8", null));
135         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
136         loadUrlAsync(aboutPageUrl);
137         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
138
139         mShouldInterceptLoadRequestHelper.setReturnValue(
140                 new WebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
141         callCount = mShouldInterceptLoadRequestHelper.getCallCount();
142         loadUrlAsync(aboutPageUrl);
143         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
144
145         mShouldInterceptLoadRequestHelper.setReturnValue(
146                 new WebResourceResponse(null, null, null));
147         callCount = mShouldInterceptLoadRequestHelper.getCallCount();
148         loadUrlAsync(aboutPageUrl);
149         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
150     }
151
152     private static class EmptyInputStream extends InputStream {
153         @Override
154         public int available() {
155             return 0;
156         }
157
158         @Override
159         public int read() throws IOException {
160             return -1;
161         }
162
163         @Override
164         public int read(byte b[]) throws IOException {
165             return -1;
166         }
167
168         @Override
169         public int read(byte b[], int off, int len) throws IOException {
170             return -1;
171         }
172
173         @Override
174         public long skip(long n) throws IOException {
175             if (n < 0)
176                 throw new IOException("skipping negative number of bytes");
177             return 0;
178         }
179     }
180
181     @SmallTest
182     @Feature({"ShouldInterceptLoadRequest"})
183     public void testDoesNotCrashOnEmptyStream() throws Throwable {
184         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
185
186         mShouldInterceptLoadRequestHelper.setReturnValue(
187                 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
188         int shouldInterceptRequestCallCount = mShouldInterceptLoadRequestHelper.getCallCount();
189         int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
190
191         loadUrlAsync(aboutPageUrl);
192
193         mShouldInterceptLoadRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
194         mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
195     }
196
197     private static class SlowWebResourceResponse extends WebResourceResponse {
198         private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
199         private CountDownLatch mLatch = new CountDownLatch(1);
200
201         public SlowWebResourceResponse(String mimeType, String encoding, InputStream data) {
202             super(mimeType, encoding, data);
203         }
204
205         @Override
206         public InputStream getData() {
207             mReadStartedCallbackHelper.notifyCalled();
208             try {
209                 mLatch.await();
210             } catch (InterruptedException e) {
211                 // ignore
212             }
213             return super.getData();
214         }
215
216         public void unblockReads() {
217             mLatch.countDown();
218         }
219
220         public CallbackHelper getReadStartedCallbackHelper() {
221             return mReadStartedCallbackHelper;
222         }
223     }
224
225     @SmallTest
226     @Feature({"ShouldInterceptLoadRequest"})
227     public void testHttpStatusField() throws Throwable {
228         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
229         final String syncGetJs =
230             "(function() {" +
231             "  var xhr = new XMLHttpRequest();" +
232             "  xhr.open('GET', '" + syncGetUrl + "', false);" +
233             "  xhr.send(null);" +
234             "  console.info('xhr.status = ' + xhr.status);" +
235             "  return xhr.status;" +
236             "})();";
237
238         getInstrumentation().runOnMainSync(new Runnable() {
239             @Override
240             public void run() {
241                 getXWalkView().getSettings().setJavaScriptEnabled(true);
242             }
243         });
244
245         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
246         loadUrlSync(aboutPageUrl);
247
248         mShouldInterceptLoadRequestHelper.setReturnValue(
249                 new WebResourceResponse("text/html", "UTF-8", null));
250         assertEquals("404", executeJavaScriptAndWaitForResult(syncGetJs));
251
252         mShouldInterceptLoadRequestHelper.setReturnValue(
253                 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
254         assertEquals("200", executeJavaScriptAndWaitForResult(syncGetJs));
255     }
256
257
258     private String makePageWithTitle(String title) {
259         return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
260                 "<div> The title is: " + title + " </div>");
261     }
262
263     @SmallTest
264     @Feature({"ShouldInterceptLoadRequest"})
265     public void testCanInterceptMainFrame() throws Throwable {
266         final String expectedTitle = "testShouldInterceptLoadRequestCanInterceptMainFrame";
267         final String expectedPage = makePageWithTitle(expectedTitle);
268
269         mShouldInterceptLoadRequestHelper.setReturnValue(
270                 stringToWebResourceResponse(expectedPage));
271
272         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
273
274         loadUrlSync(aboutPageUrl);
275
276         assertEquals(expectedTitle, getTitleOnUiThread());
277         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
278     }
279
280     @SmallTest
281     @Feature({"ShouldInterceptLoadRequest"})
282     public void testDoesNotChangeReportedUrl() throws Throwable {
283         mShouldInterceptLoadRequestHelper.setReturnValue(
284                 stringToWebResourceResponse(makePageWithTitle("some title")));
285
286         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
287
288         loadUrlSync(aboutPageUrl);
289
290         assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageFinishedHelper().getUrl());
291         assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageStartedHelper().getUrl());
292     }
293
294     @SmallTest
295     @Feature({"ShouldInterceptLoadRequest"})
296     public void testNullInputStreamCausesErrorForMainFrame() throws Throwable {
297         final OnReceivedErrorHelper onReceivedErrorHelper = mTestHelperBridge.getOnReceivedErrorHelper();
298         mShouldInterceptLoadRequestHelper.setReturnValue(
299                 new WebResourceResponse("text/html", "UTF-8", null));
300
301         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
302         final int callCount = onReceivedErrorHelper.getCallCount();
303         loadUrlAsync(aboutPageUrl);
304         onReceivedErrorHelper.waitForCallback(callCount);
305         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
306     }
307
308     @SmallTest
309     @Feature({"ShouldInterceptLoadRequest"})
310     public void testCalledForImage() throws Throwable {
311         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
312         mWebServer.setResponseBase64(imagePath,
313                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
314         final String pageWithImage =
315             addPageToTestServer(mWebServer, "/page_with_image.html",
316                     CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
317
318         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
319         loadUrlSync(pageWithImage);
320         mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 2);
321
322         assertEquals(2, mShouldInterceptLoadRequestHelper.getUrls().size());
323         assertTrue(mShouldInterceptLoadRequestHelper.getUrls().get(1).endsWith(
324                 CommonResources.FAVICON_FILENAME));
325     }
326
327     @SmallTest
328     @Feature({"ShouldInterceptLoadRequest"})
329     public void testOnReceivedErrorCallback() throws Throwable {
330         final OnReceivedErrorHelper onReceivedErrorHelper = mTestHelperBridge.getOnReceivedErrorHelper();
331         mShouldInterceptLoadRequestHelper.setReturnValue(new WebResourceResponse(null, null, null));
332         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
333         loadUrlSync("foo://bar");
334         onReceivedErrorHelper.waitForCallback(onReceivedErrorHelperCallCount, 1);
335     }
336
337     @SmallTest
338     @Feature({"ShouldInterceptLoadRequest"})
339     public void testNoOnReceivedErrorCallback() throws Throwable {
340         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
341         final String imageUrl = mWebServer.setResponseBase64(imagePath,
342                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
343         final String pageWithImage =
344                 addPageToTestServer(mWebServer, "/page_with_image.html",
345                         CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
346         final OnReceivedErrorHelper onReceivedErrorHelper = mTestHelperBridge.getOnReceivedErrorHelper();
347         mShouldInterceptLoadRequestHelper.setReturnValueForUrl(
348                 imageUrl, new WebResourceResponse(null, null, null));
349         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
350         loadUrlSync(pageWithImage);
351         assertEquals(onReceivedErrorHelperCallCount, onReceivedErrorHelper.getCallCount());
352     }
353
354     @SmallTest
355     @Feature({"ShouldInterceptLoadRequest"})
356     public void testCalledForIframe() throws Throwable {
357         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
358         final String pageWithIframe = addPageToTestServer(mWebServer, "/page_with_iframe.html",
359                 CommonResources.makeHtmlPageFrom("",
360                     "<iframe src=\"" + aboutPageUrl + "\"/>"));
361
362         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
363         // These callbacks can race with favicon.ico callback.
364         mShouldInterceptLoadRequestHelper.setUrlToWaitFor(aboutPageUrl);
365         loadUrlSync(pageWithIframe);
366
367         mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 1);
368         assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
369         assertEquals(aboutPageUrl, mShouldInterceptLoadRequestHelper.getUrls().get(0));
370     }
371
372     private void calledForUrlTemplate(final String url) throws Exception {
373         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
374         int onPageStartedCallCount = mTestHelperBridge.getOnPageStartedHelper().getCallCount();
375         loadUrlAsync(url);
376         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
377         assertEquals(url, mShouldInterceptLoadRequestHelper.getUrls().get(0));
378
379         mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
380         assertEquals(onPageStartedCallCount + 1,
381                 mTestHelperBridge.getOnPageStartedHelper().getCallCount());
382     }
383
384     private void notCalledForUrlTemplate(final String url) throws Exception {
385         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
386         loadUrlSync(url);
387         // The intercepting must happen before onPageFinished. Since the IPC messages from the
388         // renderer should be delivered in order waiting for onPageFinished is sufficient to
389         // 'flush' any pending interception messages.
390         assertEquals(callCount, mShouldInterceptLoadRequestHelper.getCallCount());
391     }
392
393     @SmallTest
394     @Feature({"ShouldInterceptLoadRequest"})
395     public void testCalledForUnsupportedSchemes() throws Throwable {
396         calledForUrlTemplate("foobar://resource/1");
397     }
398
399     @SmallTest
400     @Feature({"ShouldInterceptLoadRequest"})
401     public void testCalledForNonexistentFiles() throws Throwable {
402         calledForUrlTemplate("file:///somewhere/something");
403     }
404
405     @SmallTest
406     @Feature({"ShouldInterceptLoadRequest"})
407     public void testCalledForExistingFiles() throws Throwable {
408         final String tmpDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
409         final String fileName = tmpDir + "/testfile.html";
410         final String title = "existing file title";
411         TestFileUtil.deleteFile(fileName);  // Remove leftover file if any.
412         TestFileUtil.createNewHtmlFile(fileName, title, "");
413         final String existingFileUrl = "file://" + fileName;
414
415         int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
416         int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
417         loadUrlAsync(existingFileUrl);
418         mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
419         assertEquals(existingFileUrl, mShouldInterceptLoadRequestHelper.getUrls().get(0));
420
421         mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
422         assertEquals(title, getTitleOnUiThread());
423         assertEquals(onPageFinishedCallCount + 1,
424                 mTestHelperBridge.getOnPageFinishedHelper().getCallCount());
425     }
426
427     @SmallTest
428     @Feature({"ShouldInterceptLoadRequest"})
429     public void testNotCalledForExistingResource() throws Throwable {
430         notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
431     }
432
433     @SmallTest
434     @Feature({"ShouldInterceptLoadRequest"})
435     public void testCalledForNonexistentResource() throws Throwable {
436         calledForUrlTemplate("file:///android_res/raw/no_file.html");
437     }
438
439     @SmallTest
440     @Feature({"ShouldInterceptLoadRequest"})
441     public void testNotCalledForExistingAsset() throws Throwable {
442         notCalledForUrlTemplate("file:///android_asset/www/index.html");
443     }
444
445     @SmallTest
446     @Feature({"ShouldInterceptLoadRequest"})
447     public void testCalledForNonexistentAsset() throws Throwable {
448         calledForUrlTemplate("file:///android_res/raw/no_file.html");
449     }
450
451     @SmallTest
452     @Feature({"ShouldInterceptLoadRequest"})
453     public void testNotCalledForExistingContentUrl() throws Throwable {
454         final String contentResourceName = "target";
455         final String existingContentUrl = TestContentProvider.createContentUrl(contentResourceName);
456         TestContentProvider.resetResourceRequestCount(
457                 getInstrumentation().getTargetContext(), contentResourceName);
458
459         notCalledForUrlTemplate(existingContentUrl);
460
461         int contentRequestCount = TestContentProvider.getResourceRequestCount(
462                 getInstrumentation().getTargetContext(), contentResourceName);
463         assertEquals(1, contentRequestCount);
464     }
465
466     @SmallTest
467     @Feature({"ShouldInterceptLoadRequest"})
468     public void testCalledForNonexistentContentUrl() throws Throwable {
469         calledForUrlTemplate("content://org.xwalk.core.test.NoSuchProvider/foo");
470     }
471
472     @SmallTest
473     @Feature({"ShouldInterceptLoadRequest"})
474     public void testOnPageStartedOnlyOnMainFrame() throws Throwable {
475         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
476         final String pageWithIframe = addPageToTestServer(mWebServer, "/page_with_iframe.html",
477                 CommonResources.makeHtmlPageFrom("",
478                     "<iframe src=\"" + aboutPageUrl + "\"/>"));
479         int onPageStartedCallCount = mTestHelperBridge.getOnPageStartedHelper().getCallCount();
480
481         loadUrlSync(pageWithIframe);
482
483         mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
484         assertEquals(onPageStartedCallCount + 1,
485                 mTestHelperBridge.getOnPageStartedHelper().getCallCount());
486     }
487 }