| Index: android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
|
| diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
|
| index e87ca2c9effed42fde4587c67e00c36690fd2d85..cbc58441961a1c4baf909aa827429d7b1f3f45f1 100644
|
| --- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
|
| +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
|
| @@ -6,19 +6,23 @@ package org.chromium.android_webview.test;
|
|
|
| import android.os.Build;
|
| import android.test.suitebuilder.annotation.SmallTest;
|
| -import android.webkit.ValueCallback;
|
|
|
| import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
|
| import static org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
|
|
|
| import org.chromium.android_webview.AwContents;
|
| +import org.chromium.android_webview.AwMessagePortService;
|
| import org.chromium.android_webview.MessagePort;
|
| import org.chromium.android_webview.test.util.CommonResources;
|
| +import org.chromium.base.ThreadUtils;
|
| import org.chromium.base.test.util.DisabledTest;
|
| import org.chromium.base.test.util.Feature;
|
| import org.chromium.base.test.util.MinAndroidSdkLevel;
|
| +import org.chromium.content.browser.test.util.Criteria;
|
| +import org.chromium.content.browser.test.util.CriteriaHelper;
|
| import org.chromium.net.test.util.TestWebServer;
|
|
|
| +import java.util.concurrent.Callable;
|
| import java.util.concurrent.CountDownLatch;
|
|
|
| /**
|
| @@ -151,25 +155,18 @@ public class PostMessageTest extends AwTestBase {
|
| runTestOnUiThread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
|
| - @Override
|
| - public void onReceiveValue(MessagePort[] channel) {
|
| - mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
|
| - mWebServer.getBaseUrl(),
|
| - new MessagePort[]{channel[1]});
|
| - // retransfer the port. This should fail with an exception
|
| - try {
|
| - mAwContents.postMessageToFrame(null, "2", SOURCE_ORIGIN,
|
| - mWebServer.getBaseUrl(),
|
| - new MessagePort[]{channel[1]});
|
| - } catch (IllegalStateException ex) {
|
| - latch.countDown();
|
| - return;
|
| - }
|
| - fail();
|
| - }
|
| - };
|
| - mAwContents.createMessageChannel(callback);
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + // Retransfer the port. This should fail with an exception.
|
| + try {
|
| + mAwContents.postMessageToFrame(null, "2", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + } catch (IllegalStateException ex) {
|
| + latch.countDown();
|
| + return;
|
| + }
|
| + fail();
|
| }
|
| });
|
| boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
|
| @@ -190,19 +187,85 @@ public class PostMessageTest extends AwTestBase {
|
| runTestOnUiThread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
|
| - @Override
|
| - public void onReceiveValue(MessagePort[] channel) {
|
| - try {
|
| - channel[0].postMessage("1", new MessagePort[]{channel[0]});
|
| - } catch (IllegalStateException ex) {
|
| - latch.countDown();
|
| - return;
|
| - }
|
| - fail();
|
| - }
|
| - };
|
| - mAwContents.createMessageChannel(callback);
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + try {
|
| + channel[0].postMessage("1", new MessagePort[]{channel[0]});
|
| + } catch (IllegalStateException ex) {
|
| + latch.countDown();
|
| + return;
|
| + }
|
| + fail();
|
| + }
|
| + });
|
| + boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
|
| + }
|
| +
|
| + // Verify a closed port cannot be transferred to a frame.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testSendClosedPortToFrameNotAllowed() throws Throwable {
|
| + loadPage(TEST_PAGE);
|
| + final CountDownLatch latch = new CountDownLatch(1);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + channel[1].close();
|
| + try {
|
| + mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + } catch (IllegalStateException ex) {
|
| + latch.countDown();
|
| + return;
|
| + }
|
| + fail();
|
| + }
|
| + });
|
| + boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
|
| + }
|
| +
|
| + // Verify a closed port cannot be transferred to a port.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testSendClosedPortToPortNotAllowed() throws Throwable {
|
| + loadPage(TEST_PAGE);
|
| + final CountDownLatch latch = new CountDownLatch(1);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel1 = mAwContents.createMessageChannel();
|
| + MessagePort[] channel2 = mAwContents.createMessageChannel();
|
| + channel2[1].close();
|
| + try {
|
| + channel1[0].postMessage("1", new MessagePort[]{channel2[1]});
|
| + } catch (IllegalStateException ex) {
|
| + latch.countDown();
|
| + return;
|
| + }
|
| + fail();
|
| + }
|
| + });
|
| + boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
|
| + }
|
| +
|
| + // Verify messages cannot be posted to closed ports.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testPostMessageToClosedPortNotAllowed() throws Throwable {
|
| + loadPage(TEST_PAGE);
|
| + final CountDownLatch latch = new CountDownLatch(1);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + channel[0].close();
|
| + try {
|
| + channel[0].postMessage("1", null);
|
| + } catch (IllegalStateException ex) {
|
| + latch.countDown();
|
| + return;
|
| + }
|
| + fail();
|
| }
|
| });
|
| boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
|
| @@ -241,8 +304,7 @@ public class PostMessageTest extends AwTestBase {
|
| }
|
|
|
| // Verify that messages from JS can be waited on a UI thread.
|
| - @SmallTest
|
| - // TODO this test turned out to be flaky. When it fails, it always fails in IPC.
|
| + // TODO(sgurun) this test turned out to be flaky. When it fails, it always fails in IPC.
|
| // When a postmessage is received, an IPC message is sent from browser to renderer
|
| // to convert the postmessage from WebSerializedScriptValue to a string. The IPC is sent
|
| // and seems to be received by IPC in renderer, but then nothing else seems to happen.
|
| @@ -257,22 +319,17 @@ public class PostMessageTest extends AwTestBase {
|
| runTestOnUiThread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + // verify communication from JS to Java.
|
| + channelContainer.set(channel);
|
| + channel[0].setMessageHandler(new MessagePort.MessageHandler() {
|
| @Override
|
| - public void onReceiveValue(MessagePort[] channel) {
|
| - // verify communication from JS to Java.
|
| - channelContainer.set(channel);
|
| - channel[0].setMessageHandler(new MessagePort.MessageHandler() {
|
| - @Override
|
| - public void onMessage(String message) {
|
| - channelContainer.setMessage(message);
|
| - }
|
| - });
|
| - mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| - mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + public void onMessage(String message) {
|
| + channelContainer.setMessage(message);
|
| }
|
| - };
|
| - mAwContents.createMessageChannel(callback);
|
| + });
|
| + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| }
|
| });
|
| mMessageObject.waitForMessage();
|
| @@ -305,38 +362,251 @@ public class PostMessageTest extends AwTestBase {
|
| + " </script>"
|
| + "</body></html>";
|
|
|
| - // Verify that a channel can be created and basic full duplex communication
|
| - // can happen on it. Do this by sending a message to JS and let it echo'ing
|
| - // the message with some text prepended to it.
|
| +
|
| + // Call on non-UI thread.
|
| + private void waitUntilPortReady(final MessagePort port) throws Throwable {
|
| + CriteriaHelper.pollForCriteria(new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return ThreadUtils.runOnUiThreadBlockingNoException(
|
| + new Callable<Boolean>() {
|
| + @Override
|
| + public Boolean call() throws Exception {
|
| + return port.isReady();
|
| + }
|
| + });
|
| + }
|
| + });
|
| + }
|
| +
|
| + private static final String HELLO = "HELLO";
|
| +
|
| + // Message channels are created on UI thread in a pending state. They are
|
| + // initialized at a later stage. Verify that a message port that is initialized
|
| + // can be transferred to JS and full communication can happen on it.
|
| + // Do this by sending a message to JS and let it echo'ing the message with
|
| + // some text prepended to it.
|
| @SmallTest
|
| @Feature({"AndroidWebView", "Android-PostMessage"})
|
| - public void testMessageChannel() throws Throwable {
|
| - final String hello = "HELLO";
|
| + public void testMessageChannelUsingInitializedPort() throws Throwable {
|
| final ChannelContainer channelContainer = new ChannelContainer();
|
| loadPage(ECHO_PAGE);
|
| + final MessagePort[] channel = ThreadUtils.runOnUiThreadBlocking(
|
| + new Callable<MessagePort[]>() {
|
| + @Override
|
| + public MessagePort[] call() {
|
| + return mAwContents.createMessageChannel();
|
| + }
|
| + });
|
| +
|
| + waitUntilPortReady(channel[0]);
|
| + waitUntilPortReady(channel[1]);
|
| runTestOnUiThread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
|
| + channel[0].setMessageHandler(new MessagePort.MessageHandler() {
|
| @Override
|
| - public void onReceiveValue(MessagePort[] channel) {
|
| - channel[0].setMessageHandler(new MessagePort.MessageHandler() {
|
| - @Override
|
| - public void onMessage(String message) {
|
| - channelContainer.setMessage(message);
|
| - }
|
| - });
|
| - mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| - mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| - channel[0].postMessage(hello, null);
|
| + public void onMessage(String message) {
|
| + channelContainer.setMessage(message);
|
| }
|
| - };
|
| - mAwContents.createMessageChannel(callback);
|
| + });
|
| + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + channel[0].postMessage(HELLO, null);
|
| }
|
| });
|
| // wait for the asynchronous response from JS
|
| channelContainer.waitForMessage();
|
| - assertEquals(hello + JS_MESSAGE, channelContainer.getMessage());
|
| + assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage());
|
| + }
|
| +
|
| + // Verify that a message port can be used immediately (even if it is in
|
| + // pending state) after creation. In particular make sure the message port can be
|
| + // transferred to JS and full communication can happen on it.
|
| + // Do this by sending a message to JS and let it echo'ing the message with
|
| + // some text prepended to it.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testMessageChannelUsingPendingPort() throws Throwable {
|
| + final ChannelContainer channelContainer = new ChannelContainer();
|
| + loadPage(ECHO_PAGE);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + channel[0].setMessageHandler(new MessagePort.MessageHandler() {
|
| + @Override
|
| + public void onMessage(String message) {
|
| + channelContainer.setMessage(message);
|
| + }
|
| + });
|
| + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + channel[0].postMessage(HELLO, null);
|
| + }
|
| + });
|
| + // Wait for the asynchronous response from JS.
|
| + channelContainer.waitForMessage();
|
| + assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage());
|
| + }
|
| +
|
| + // Verify that a message port can be used for message transfer when both
|
| + // ports are owned by same Webview.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testMessageChannelCommunicationWithinWebView() throws Throwable {
|
| + final ChannelContainer channelContainer = new ChannelContainer();
|
| + loadPage(ECHO_PAGE);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + channel[1].setMessageHandler(new MessagePort.MessageHandler() {
|
| + @Override
|
| + public void onMessage(String message) {
|
| + channelContainer.setMessage(message);
|
| + }
|
| + });
|
| + channel[0].postMessage(HELLO, null);
|
| + }
|
| + });
|
| + // Wait for the asynchronous response from JS.
|
| + channelContainer.waitForMessage();
|
| + assertEquals(HELLO, channelContainer.getMessage());
|
| + }
|
| +
|
| + // concats all the data fields of the received messages and makes it
|
| + // available as page title.
|
| + private static final String TITLE_PAGE =
|
| + "<!DOCTYPE html><html><body>"
|
| + + " <script>"
|
| + + " var received = \"\";"
|
| + + " onmessage = function (e) {"
|
| + + " received = received + e.data;"
|
| + + " document.title = received;"
|
| + + " }"
|
| + + " </script>"
|
| + + "</body></html>";
|
| +
|
| + // Call on non-UI thread.
|
| + private void expectTitle(final String title) throws Throwable {
|
| + assertTrue("Received title " + mAwContents.getTitle() + " while expecting " + title,
|
| + CriteriaHelper.pollForCriteria(new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return ThreadUtils.runOnUiThreadBlockingNoException(
|
| + new Callable<Boolean>() {
|
| + @Override
|
| + public Boolean call() throws Exception {
|
| + return mAwContents.getTitle().equals(title);
|
| + }
|
| + });
|
| + }
|
| + }));
|
| + }
|
| +
|
| + // Post a message with a pending port to a frame and then post a bunch of messages
|
| + // after that. Make sure that they are not ordered at the receiver side.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testPostMessageToFrameNotReordersMessages() throws Throwable {
|
| + loadPage(TITLE_PAGE);
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + mAwContents.postMessageToFrame(null, "2", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), null);
|
| + mAwContents.postMessageToFrame(null, "3", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), null);
|
| + }
|
| + });
|
| + expectTitle("123");
|
| + }
|
| +
|
| + private static class TestMessagePort extends MessagePort {
|
| +
|
| + private boolean mReady;
|
| + private MessagePort mPort;
|
| + private Object mLock = new Object();
|
| +
|
| + public TestMessagePort(AwMessagePortService service) {
|
| + super(service);
|
| + }
|
| +
|
| + public void setMessagePort(MessagePort port) {
|
| + mPort = port;
|
| + }
|
| +
|
| + public void setReady(boolean ready) {
|
| + synchronized (mLock) {
|
| + mReady = ready;
|
| + }
|
| + }
|
| + @Override
|
| + public boolean isReady() {
|
| + synchronized (mLock) {
|
| + return mReady;
|
| + }
|
| + }
|
| + @Override
|
| + public int portId() {
|
| + return mPort.portId();
|
| + }
|
| + @Override
|
| + public void setPortId(int id) {
|
| + mPort.setPortId(id);
|
| + }
|
| + @Override
|
| + public void close() {
|
| + mPort.close();
|
| + }
|
| + @Override
|
| + public boolean isClosed() {
|
| + return mPort.isClosed();
|
| + }
|
| + @Override
|
| + public void setMessageHandler(MessageHandler handler) {
|
| + mPort.setMessageHandler(handler);
|
| + }
|
| + @Override
|
| + public void onMessage(String message) {
|
| + mPort.onMessage(message);
|
| + }
|
| + @Override
|
| + public void postMessage(String message, MessagePort[] msgPorts) throws
|
| + IllegalStateException {
|
| + mPort.postMessage(message, msgPorts);
|
| + }
|
| + }
|
| +
|
| + // Post a message with a pending port to a frame and then post a message that
|
| + // is pending after that. Make sure that when first message becomes ready,
|
| + // the subsequent not-ready message is not sent.
|
| + @SmallTest
|
| + @Feature({"AndroidWebView", "Android-PostMessage"})
|
| + public void testPostMessageToFrameNotSendsPendingMessages() throws Throwable {
|
| + loadPage(TITLE_PAGE);
|
| + final TestMessagePort testPort =
|
| + new TestMessagePort(getAwBrowserContext().getMessagePortService());
|
| + runTestOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
|
| + mAwContents.postMessageToFrame(null, "2", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), null);
|
| + MessagePort[] channel2 = mAwContents.createMessageChannel();
|
| + // Test port is in a pending state so it should not be transferred.
|
| + testPort.setMessagePort(channel2[0]);
|
| + mAwContents.postMessageToFrame(null, "3", SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{testPort});
|
| + }
|
| + });
|
| + expectTitle("12");
|
| }
|
|
|
| private static final String WORKER_MESSAGE = "from_worker";
|
| @@ -371,6 +641,8 @@ public class PostMessageTest extends AwTestBase {
|
| + " }"
|
| + "}";
|
|
|
| + // Test if message ports created at the native side can be transferred
|
| + // to JS side, to establish a communication channel between a worker and a frame.
|
| @SmallTest
|
| @Feature({"AndroidWebView", "Android-PostMessage"})
|
| public void testTransferPortsToWorker() throws Throwable {
|
| @@ -380,15 +652,9 @@ public class PostMessageTest extends AwTestBase {
|
| runTestOnUiThread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
|
| - @Override
|
| - public void onReceiveValue(MessagePort[] channel) {
|
| - mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| - mWebServer.getBaseUrl(),
|
| - new MessagePort[]{channel[0], channel[1]});
|
| - }
|
| - };
|
| - mAwContents.createMessageChannel(callback);
|
| + MessagePort[] channel = mAwContents.createMessageChannel();
|
| + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
|
| + mWebServer.getBaseUrl(), new MessagePort[]{channel[0], channel[1]});
|
| }
|
| });
|
| mMessageObject.waitForMessage();
|
|
|