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 setXWalkClient(new XWalkViewTestBase.TestXWalkClient());
78 getInstrumentation().runOnMainSync(new Runnable() {
81 mTestXWalkResourceClient = new TestXWalkResourceClient1();
82 getXWalkView().setResourceClient(mTestXWalkResourceClient);
83 mShouldInterceptLoadRequestHelper = mTestHelperBridge.getShouldInterceptLoadRequestHelper();
84 mOnLoadStartedHelper = mTestHelperBridge.getOnLoadStartedHelper();
88 mWebServer = new TestWebServer(false);
92 protected void tearDown() throws Exception {
93 mWebServer.shutdown();
98 @Feature({"ShouldInterceptLoadRequest"})
99 public void testCalledWithCorrectUrl() throws Throwable {
100 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
102 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
103 int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
105 loadUrlAsync(aboutPageUrl);
107 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
108 assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
109 assertEquals(aboutPageUrl,
110 mShouldInterceptLoadRequestHelper.getUrls().get(0));
112 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
113 assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread());
117 @Feature({"ShouldInterceptLoadRequest"})
118 public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
119 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
120 int callCount = mOnLoadStartedHelper.getCallCount();
122 loadUrlAsync(aboutPageUrl);
124 mOnLoadStartedHelper.waitForCallback(callCount);
125 assertEquals(aboutPageUrl, mOnLoadStartedHelper.getUrl());
129 @Feature({"ShouldInterceptLoadRequest"})
130 public void testDoesNotCrashOnInvalidData() throws Throwable {
131 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
133 mShouldInterceptLoadRequestHelper.setReturnValue(
134 new WebResourceResponse("text/html", "UTF-8", null));
135 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
136 loadUrlAsync(aboutPageUrl);
137 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
139 mShouldInterceptLoadRequestHelper.setReturnValue(
140 new WebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
141 callCount = mShouldInterceptLoadRequestHelper.getCallCount();
142 loadUrlAsync(aboutPageUrl);
143 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
145 mShouldInterceptLoadRequestHelper.setReturnValue(
146 new WebResourceResponse(null, null, null));
147 callCount = mShouldInterceptLoadRequestHelper.getCallCount();
148 loadUrlAsync(aboutPageUrl);
149 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
152 private static class EmptyInputStream extends InputStream {
154 public int available() {
159 public int read() throws IOException {
164 public int read(byte b[]) throws IOException {
169 public int read(byte b[], int off, int len) throws IOException {
174 public long skip(long n) throws IOException {
176 throw new IOException("skipping negative number of bytes");
182 @Feature({"ShouldInterceptLoadRequest"})
183 public void testDoesNotCrashOnEmptyStream() throws Throwable {
184 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
186 mShouldInterceptLoadRequestHelper.setReturnValue(
187 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
188 int shouldInterceptRequestCallCount = mShouldInterceptLoadRequestHelper.getCallCount();
189 int onPageFinishedCallCount = mTestHelperBridge.getOnPageFinishedHelper().getCallCount();
191 loadUrlAsync(aboutPageUrl);
193 mShouldInterceptLoadRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
194 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
197 private static class SlowWebResourceResponse extends WebResourceResponse {
198 private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
199 private CountDownLatch mLatch = new CountDownLatch(1);
201 public SlowWebResourceResponse(String mimeType, String encoding, InputStream data) {
202 super(mimeType, encoding, data);
206 public InputStream getData() {
207 mReadStartedCallbackHelper.notifyCalled();
210 } catch (InterruptedException e) {
213 return super.getData();
216 public void unblockReads() {
220 public CallbackHelper getReadStartedCallbackHelper() {
221 return mReadStartedCallbackHelper;
226 @Feature({"ShouldInterceptLoadRequest"})
227 public void testHttpStatusField() throws Throwable {
228 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
229 final String syncGetJs =
231 " var xhr = new XMLHttpRequest();" +
232 " xhr.open('GET', '" + syncGetUrl + "', false);" +
234 " console.info('xhr.status = ' + xhr.status);" +
235 " return xhr.status;" +
238 getInstrumentation().runOnMainSync(new Runnable() {
241 getXWalkView().getSettings().setJavaScriptEnabled(true);
245 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
246 loadUrlSync(aboutPageUrl);
248 mShouldInterceptLoadRequestHelper.setReturnValue(
249 new WebResourceResponse("text/html", "UTF-8", null));
250 assertEquals("404", executeJavaScriptAndWaitForResult(syncGetJs));
252 mShouldInterceptLoadRequestHelper.setReturnValue(
253 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
254 assertEquals("200", executeJavaScriptAndWaitForResult(syncGetJs));
258 private String makePageWithTitle(String title) {
259 return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
260 "<div> The title is: " + title + " </div>");
264 @Feature({"ShouldInterceptLoadRequest"})
265 public void testCanInterceptMainFrame() throws Throwable {
266 final String expectedTitle = "testShouldInterceptLoadRequestCanInterceptMainFrame";
267 final String expectedPage = makePageWithTitle(expectedTitle);
269 mShouldInterceptLoadRequestHelper.setReturnValue(
270 stringToWebResourceResponse(expectedPage));
272 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
274 loadUrlSync(aboutPageUrl);
276 assertEquals(expectedTitle, getTitleOnUiThread());
277 assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
281 @Feature({"ShouldInterceptLoadRequest"})
282 public void testDoesNotChangeReportedUrl() throws Throwable {
283 mShouldInterceptLoadRequestHelper.setReturnValue(
284 stringToWebResourceResponse(makePageWithTitle("some title")));
286 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
288 loadUrlSync(aboutPageUrl);
290 assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageFinishedHelper().getUrl());
291 assertEquals(aboutPageUrl, mTestHelperBridge.getOnPageStartedHelper().getUrl());
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));
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));
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));
318 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
319 loadUrlSync(pageWithImage);
320 mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 2);
322 assertEquals(2, mShouldInterceptLoadRequestHelper.getUrls().size());
323 assertTrue(mShouldInterceptLoadRequestHelper.getUrls().get(1).endsWith(
324 CommonResources.FAVICON_FILENAME));
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);
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());
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 + "\"/>"));
362 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
363 // These callbacks can race with favicon.ico callback.
364 mShouldInterceptLoadRequestHelper.setUrlToWaitFor(aboutPageUrl);
365 loadUrlSync(pageWithIframe);
367 mShouldInterceptLoadRequestHelper.waitForCallback(callCount, 1);
368 assertEquals(1, mShouldInterceptLoadRequestHelper.getUrls().size());
369 assertEquals(aboutPageUrl, mShouldInterceptLoadRequestHelper.getUrls().get(0));
372 private void calledForUrlTemplate(final String url) throws Exception {
373 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
374 int onPageStartedCallCount = mTestHelperBridge.getOnPageStartedHelper().getCallCount();
376 mShouldInterceptLoadRequestHelper.waitForCallback(callCount);
377 assertEquals(url, mShouldInterceptLoadRequestHelper.getUrls().get(0));
379 mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
380 assertEquals(onPageStartedCallCount + 1,
381 mTestHelperBridge.getOnPageStartedHelper().getCallCount());
384 private void notCalledForUrlTemplate(final String url) throws Exception {
385 int callCount = mShouldInterceptLoadRequestHelper.getCallCount();
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());
394 @Feature({"ShouldInterceptLoadRequest"})
395 public void testCalledForUnsupportedSchemes() throws Throwable {
396 calledForUrlTemplate("foobar://resource/1");
400 @Feature({"ShouldInterceptLoadRequest"})
401 public void testCalledForNonexistentFiles() throws Throwable {
402 calledForUrlTemplate("file:///somewhere/something");
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;
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));
421 mTestHelperBridge.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
422 assertEquals(title, getTitleOnUiThread());
423 assertEquals(onPageFinishedCallCount + 1,
424 mTestHelperBridge.getOnPageFinishedHelper().getCallCount());
428 @Feature({"ShouldInterceptLoadRequest"})
429 public void testNotCalledForExistingResource() throws Throwable {
430 notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
434 @Feature({"ShouldInterceptLoadRequest"})
435 public void testCalledForNonexistentResource() throws Throwable {
436 calledForUrlTemplate("file:///android_res/raw/no_file.html");
440 @Feature({"ShouldInterceptLoadRequest"})
441 public void testNotCalledForExistingAsset() throws Throwable {
442 notCalledForUrlTemplate("file:///android_asset/www/index.html");
446 @Feature({"ShouldInterceptLoadRequest"})
447 public void testCalledForNonexistentAsset() throws Throwable {
448 calledForUrlTemplate("file:///android_res/raw/no_file.html");
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);
459 notCalledForUrlTemplate(existingContentUrl);
461 int contentRequestCount = TestContentProvider.getResourceRequestCount(
462 getInstrumentation().getTargetContext(), contentResourceName);
463 assertEquals(1, contentRequestCount);
467 @Feature({"ShouldInterceptLoadRequest"})
468 public void testCalledForNonexistentContentUrl() throws Throwable {
469 calledForUrlTemplate("content://org.xwalk.core.test.NoSuchProvider/foo");
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();
481 loadUrlSync(pageWithIframe);
483 mTestHelperBridge.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
484 assertEquals(onPageStartedCallCount + 1,
485 mTestHelperBridge.getOnPageStartedHelper().getCallCount());