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