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.
6 package org.xwalk.core.xwview.test;
8 import android.test.suitebuilder.annotation.SmallTest;
9 import android.util.Pair;
10 import android.webkit.WebResourceResponse;
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;
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;
26 import org.xwalk.core.XWalkView;
27 import org.xwalk.core.xwview.test.TestContentProvider;
28 import org.xwalk.core.xwview.test.util.CommonResources;
31 * Test case for XWalkResourceClient.shouldInterceptRequest callback
33 * Note the major part of this file is migrated from android_webview/.
35 public class ShouldInterceptLoadRequestTest extends XWalkViewTestBase {
38 * Customized XWalkResourceClient implementation for shouldInterceptRequest
40 private class TestXWalkResourceClient1 extends XWalkViewTestBase.TestXWalkResourceClient {
42 public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
43 return mTestHelperBridge.shouldInterceptLoadRequest(url);
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);
55 private String addAboutPageToTestServer(TestWebServer webServer) {
56 return addPageToTestServer(webServer, "/" + CommonResources.ABOUT_FILENAME,
57 CommonResources.ABOUT_HTML);
60 private WebResourceResponse stringToWebResourceResponse(String input) throws Throwable {
61 final String mimeType = "text/html";
62 final String encoding = "UTF-8";
64 return new WebResourceResponse(
65 mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding)));
68 private TestWebServer mWebServer;
69 private TestXWalkResourceClient1 mTestXWalkResourceClient;
70 private TestHelperBridge.ShouldInterceptLoadRequestHelper mShouldInterceptLoadRequestHelper;
71 private TestHelperBridge.OnLoadStartedHelper mOnLoadStartedHelper;
74 protected void setUp() throws Exception {
77 getInstrumentation().runOnMainSync(new Runnable() {
80 mTestXWalkResourceClient = new TestXWalkResourceClient1();
81 getXWalkView().setResourceClient(mTestXWalkResourceClient);
82 mShouldInterceptLoadRequestHelper = mTestHelperBridge.getShouldInterceptLoadRequestHelper();
83 mOnLoadStartedHelper = mTestHelperBridge.getOnLoadStartedHelper();
87 mWebServer = new TestWebServer(false);
91 protected void tearDown() throws Exception {
92 mWebServer.shutdown();
97 @Feature({"ShouldInterceptLoadRequest"})
98 public void testCalledWithCorrectUrl() throws Throwable {
99 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
101 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
102 int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
104 loadUrlAsync(aboutPageUrl);
106 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
107 assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
108 assertEquals(aboutPageUrl,
109 mShouldInterceptLoadRequestHelper.getUrls().get(0));
111 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
112 assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread());
116 @Feature({"ShouldInterceptLoadRequest"})
117 public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
118 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
119 int callCount = mOnLoadStartedHelper.getCallCount();
121 loadUrlAsync(aboutPageUrl);
123 mOnLoadStartedHelper.waitForCallback(callCount);
124 assertEquals(aboutPageUrl, mOnLoadStartedHelper.getUrl());
128 @Feature({"ShouldInterceptLoadRequest"})
129 public void testDoesNotCrashOnInvalidData() throws Throwable {
130 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
132 mShouldInterceptLoadRequestHelper.setReturnValue(
133 new WebResourceResponse("text/html", "UTF-8", null));
134 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
135 loadUrlAsync(aboutPageUrl);
136 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
138 mShouldInterceptLoadRequestHelper.setReturnValue(
139 new WebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
140 callCount = mShouldInterceptLoadRequestHelper.getCallCount();
141 loadUrlAsync(aboutPageUrl);
142 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
144 mShouldInterceptLoadRequestHelper.setReturnValue(
145 new WebResourceResponse(null, null, null));
146 callCount = mShouldInterceptLoadRequestHelper.getCallCount();
147 loadUrlAsync(aboutPageUrl);
148 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
151 private static class EmptyInputStream extends InputStream {
153 public int available() {
158 public int read() throws IOException {
163 public int read(byte b[]) throws IOException {
168 public int read(byte b[], int off, int len) throws IOException {
173 public long skip(long n) throws IOException {
175 throw new IOException("skipping negative number of bytes");
181 @Feature({"ShouldInterceptLoadRequest"})
182 public void testDoesNotCrashOnEmptyStream() throws Throwable {
183 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
185 mShouldInterceptLoadRequestHelper.setReturnValue(
186 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
187 int shouldInterceptRequestCallCount = mShouldInterceptLoadRequestHelper.getCallCount();
188 int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
190 loadUrlAsync(aboutPageUrl);
192 mShouldInterceptLoadRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
193 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
196 private static class SlowWebResourceResponse extends WebResourceResponse {
197 private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
198 private CountDownLatch mLatch = new CountDownLatch(1);
200 public SlowWebResourceResponse(String mimeType, String encoding, InputStream data) {
201 super(mimeType, encoding, data);
205 public InputStream getData() {
206 mReadStartedCallbackHelper.notifyCalled();
209 } catch (InterruptedException e) {
212 return super.getData();
215 public void unblockReads() {
219 public CallbackHelper getReadStartedCallbackHelper() {
220 return mReadStartedCallbackHelper;
225 @Feature({"ShouldInterceptLoadRequest"})
226 public void testHttpStatusField() throws Throwable {
227 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
228 final String syncGetJs =
230 " var xhr = new XMLHttpRequest();" +
231 " xhr.open('GET', '" + syncGetUrl + "', false);" +
233 " console.info('xhr.status = ' + xhr.status);" +
234 " return xhr.status;" +
237 getInstrumentation().runOnMainSync(new Runnable() {
240 getXWalkView().getSettings().setJavaScriptEnabled(true);
244 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
245 loadUrlSync(aboutPageUrl);
247 mShouldInterceptLoadRequestHelper.setReturnValue(
248 new WebResourceResponse("text/html", "UTF-8", null));
249 assertEquals("404", executeJavaScriptAndWaitForResult(syncGetJs));
251 mShouldInterceptLoadRequestHelper.setReturnValue(
252 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
253 assertEquals("200", executeJavaScriptAndWaitForResult(syncGetJs));
257 private String makePageWithTitle(String title) {
258 return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
259 "<div> The title is: " + title + " </div>");
263 @Feature({"ShouldInterceptLoadRequest"})
264 public void testCanInterceptMainFrame() throws Throwable {
265 final String expectedTitle = "testShouldInterceptLoadRequestCanInterceptMainFrame";
266 final String expectedPage = makePageWithTitle(expectedTitle);
268 mShouldInterceptLoadRequestHelper.setReturnValue(
269 stringToWebResourceResponse(expectedPage));
271 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
273 loadUrlSync(aboutPageUrl);
275 assertEquals(expectedTitle, getTitleOnUiThread());
276 assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
280 @Feature({"ShouldInterceptLoadRequest"})
281 public void testDoesNotChangeReportedUrl() throws Throwable {
282 mShouldInterceptLoadRequestHelper.setReturnValue(
283 stringToWebResourceResponse(makePageWithTitle("some title")));
285 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
287 loadUrlSync(aboutPageUrl);
289 assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageFinishedHelper().getUrl());
290 assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageStartedHelper().getUrl());
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));
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));
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));
317 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
318 loadUrlSync(pageWithImage);
319 mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 2);
321 assertEquals(2, mShouldInterceptLoadRequestHelper.getUrls().size());
322 assertTrue(mShouldInterceptLoadRequestHelper.getUrls().get(1).endsWith(
323 CommonResources.FAVICON_FILENAME));
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);
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());
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 + "\"/>"));
361 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
362 // These callbacks can race with favicon.ico callback.
363 mShouldInterceptLoadRequestHelper.setUrlToWaitFor(aboutPageUrl);
364 loadUrlSync(pageWithIframe);
366 mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 1);
367 assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
368 assertEquals(aboutPageUrl, mShouldInterceptLoadRequestHelper.getUrls().get(0));
371 private void calledForUrlTemplate(final String url) throws Exception {
372 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
373 int onPageStartedCallCount = mTestHelperBridge.getOnPageStartedHelper().getCallCount();
375 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
376 assertEquals(url, mShouldInterceptLoadRequestHelper.getUrls().get(0));
378 mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
379 assertEquals(onPageStartedCallCount + 1,
380 mTestHelperBridge.getOnPageStartedHelper().getCallCount());
383 private void notCalledForUrlTemplate(final String url) throws Exception {
384 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
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());
393 @Feature({"ShouldInterceptLoadRequest"})
394 public void testCalledForUnsupportedSchemes() throws Throwable {
395 calledForUrlTemplate("foobar://resource/1");
399 @Feature({"ShouldInterceptLoadRequest"})
400 public void testCalledForNonexistentFiles() throws Throwable {
401 calledForUrlTemplate("file:///somewhere/something");
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;
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));
420 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
421 assertEquals(title, getTitleOnUiThread());
422 assertEquals(onPageFinishedCallCount + 1,
423 mTestHelperBridge.getOnPageFinishedHelper().getCallCount());
427 @Feature({"ShouldInterceptLoadRequest"})
428 public void testNotCalledForExistingResource() throws Throwable {
429 notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
433 @Feature({"ShouldInterceptLoadRequest"})
434 public void testCalledForNonexistentResource() throws Throwable {
435 calledForUrlTemplate("file:///android_res/raw/no_file.html");
439 @Feature({"ShouldInterceptLoadRequest"})
440 public void testNotCalledForExistingAsset() throws Throwable {
441 notCalledForUrlTemplate("file:///android_asset/www/index.html");
445 @Feature({"ShouldInterceptLoadRequest"})
446 public void testCalledForNonexistentAsset() throws Throwable {
447 calledForUrlTemplate("file:///android_res/raw/no_file.html");
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);
458 notCalledForUrlTemplate(existingContentUrl);
460 int contentRequestCount = TestContentProvider.getResourceRequestCount(
461 getInstrumentation().getTargetContext(), contentResourceName);
462 assertEquals(1, contentRequestCount);
466 @Feature({"ShouldInterceptLoadRequest"})
467 public void testCalledForNonexistentContentUrl() throws Throwable {
468 calledForUrlTemplate("content://org.xwalk.core.test.NoSuchProvider/foo");
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();
480 loadUrlSync(pageWithIframe);
482 mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
483 assertEquals(onPageStartedCallCount + 1,
484 mTestHelperBridge.getOnPageStartedHelper().getCallCount());