Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Unified Diff: components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java

Issue 1412243012: Initial implementation of CronetBidirectionalStream. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Helen's comments. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
index 7e10f83848659065eab8f06ab80b2363da4208dc..6dcc759f300e4f6fb40ad5f3f86242da41af38cd 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -4,15 +4,22 @@
package org.chromium.net;
+import android.os.ConditionVariable;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.test.util.Feature;
+import org.chromium.net.CronetTestBase.OnlyRunNativeCronet;
+import org.chromium.net.TestBidirectionalStreamCallback.FailureType;
+import org.chromium.net.TestBidirectionalStreamCallback.ResponseStep;
import java.nio.ByteBuffer;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Test functionality of BidirectionalStream interface.
@@ -23,63 +30,71 @@ public class BidirectionalStreamTest extends CronetTestBase {
@Override
protected void setUp() throws Exception {
super.setUp();
- mTestFramework = startCronetTestFramework();
- assertTrue(NativeTestServer.startNativeTestServer(getContext()));
- // Add url interceptors after native application context is initialized.
- MockUrlRequestJobFactory.setUp();
+ // Load library first to create MockCertVerifier.
+ System.loadLibrary("cronet_tests");
+ CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
+ builder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerifier());
+
+ mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, builder);
+ assertTrue(Http2TestServer.startHttp2TestServer(
+ getContext(), QuicTestServer.getServerCert(), QuicTestServer.getServerCertKey()));
}
@Override
protected void tearDown() throws Exception {
- NativeTestServer.shutdownNativeTestServer();
- mTestFramework.mCronetEngine.shutdown();
+ assertTrue(Http2TestServer.shutdownHttp2TestServer());
+ if (mTestFramework.mCronetEngine != null) {
+ mTestFramework.mCronetEngine.shutdown();
+ }
super.tearDown();
}
- private class TestBidirectionalStreamCallback extends BidirectionalStream.Callback {
- // Executor Service for Cronet callbacks.
- private final ExecutorService mExecutorService =
- Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
- private Thread mExecutorThread;
-
- private class ExecutorThreadFactory implements ThreadFactory {
- public Thread newThread(Runnable r) {
- mExecutorThread = new Thread(r);
- return mExecutorThread;
- }
- }
-
- @Override
- public void onRequestHeadersSent(BidirectionalStream stream) {}
-
- @Override
- public void onResponseHeadersReceived(BidirectionalStream stream, UrlResponseInfo info) {}
-
- @Override
- public void onReadCompleted(
- BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buffer) {}
-
- @Override
- public void onWriteCompleted(
- BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buffer) {}
-
- @Override
- public void onResponseTrailersReceived(BidirectionalStream stream, UrlResponseInfo info,
- UrlResponseInfo.HeaderBlock trailers) {}
+ private TestBidirectionalStreamCallback startAndWaitForComplete(String url) throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
- @Override
- public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info) {}
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .setHttpMethod("GET")
+ .build();
+ stream.start();
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ return callback;
+ }
- @Override
- public void onFailed(
- BidirectionalStream stream, UrlResponseInfo info, CronetException error) {}
+ private static void checkResponseInfo(UrlResponseInfo responseInfo, String expectedUrl,
+ int expectedHttpStatusCode, String expectedHttpStatusText) {
+ assertEquals(expectedUrl, responseInfo.getUrl());
+ assertEquals(
+ expectedUrl, responseInfo.getUrlChain().get(responseInfo.getUrlChain().size() - 1));
+ assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode());
+ assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText());
+ assertFalse(responseInfo.wasCached());
+ assertTrue(responseInfo.toString().length() > 0);
+ }
- @Override
- public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {}
+ private static String makeLongString(String base, int repetition) {
+ StringBuilder builder = new StringBuilder(base.length() * repetition);
+ for (int i = 0; i < repetition; ++i) {
+ builder.append(i);
+ builder.append(base);
+ }
+ return builder.toString();
+ }
- Executor getExecutor() {
- return mExecutorService;
+ private static UrlResponseInfo createUrlResponseInfo(
+ String[] urls, String message, int statusCode, int receivedBytes, String... headers) {
+ ArrayList<Map.Entry<String, String>> headersList = new ArrayList<>();
+ for (int i = 0; i < headers.length; i += 2) {
+ headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>(
+ headers[i], headers[i + 1]));
}
+ UrlResponseInfo unknown = new UrlResponseInfo(
+ Arrays.asList(urls), statusCode, message, headersList, false, "h2", null);
+ unknown.setReceivedBytesCount(receivedBytes);
+ return unknown;
}
@SmallTest
@@ -94,28 +109,725 @@ public class BidirectionalStreamTest extends CronetTestBase {
assertEquals("URL is required.", e.getMessage());
}
try {
- new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), null,
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), null,
callback.getExecutor(), mTestFramework.mCronetEngine);
fail("Callback not null-checked");
} catch (NullPointerException e) {
assertEquals("Callback is required.", e.getMessage());
}
try {
- new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callback, null,
- mTestFramework.mCronetEngine);
+ new BidirectionalStream.Builder(
+ Http2TestServer.getServerUrl(), callback, null, mTestFramework.mCronetEngine);
fail("Executor not null-checked");
} catch (NullPointerException e) {
assertEquals("Executor is required.", e.getMessage());
}
try {
new BidirectionalStream.Builder(
- NativeTestServer.getRedirectURL(), callback, callback.getExecutor(), null);
+ Http2TestServer.getServerUrl(), callback, callback.getExecutor(), null);
fail("CronetEngine not null-checked");
} catch (NullPointerException e) {
assertEquals("CronetEngine is required.", e.getMessage());
}
// Verify successful creation doesn't throw.
- new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callback,
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
callback.getExecutor(), mTestFramework.mCronetEngine);
}
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testFailPlainHttp() throws Exception {
+ String url = "http://example.com";
+ TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
+ assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_SCHEME",
+ callback.mError.getMessage());
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testSimpleGet() throws Exception {
+ String url = Http2TestServer.getEchoMethodUrl();
+ TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ // Default method is 'GET'.
+ assertEquals("GET", callback.mResponseAsString);
+ UrlResponseInfo urlResponseInfo =
+ createUrlResponseInfo(new String[] {url}, "", 200, 27, ":status", "200");
+ assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
+ checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodUrl(), 200, "");
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testSimpleHead() throws Exception {
+ String url = Http2TestServer.getEchoMethodUrl();
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .setHttpMethod("HEAD")
+ .build();
+ stream.start();
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("HEAD", callback.mResponseAsString);
+ UrlResponseInfo urlResponseInfo =
+ createUrlResponseInfo(new String[] {url}, "", 200, 28, ":status", "200");
+ assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
+ checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodUrl(), 200, "");
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testSimplePost() throws Exception {
+ String url = Http2TestServer.getEchoStreamUrl();
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.addWriteData("Test String".getBytes());
+ callback.addWriteData("1234567890".getBytes());
+ callback.addWriteData("woot!".getBytes());
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .addHeader("foo", "bar")
+ .addHeader("Content-Type", "zebra")
+ .build();
+ stream.start();
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("Test String1234567890woot!", callback.mResponseAsString);
+ assertEquals("bar", callback.mResponseInfo.getAllHeaders().get("echo-foo").get(0));
+ assertEquals(
+ "zebra", callback.mResponseInfo.getAllHeaders().get("echo-content-type").get(0));
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testSetHttpMethod() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.addWriteData("Put This Data!".getBytes());
+ String methodName = "PUT";
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ // Try to set 'null' method.
+ try {
+ builder.setHttpMethod(null);
+ fail("Exception not thrown");
+ } catch (NullPointerException e) {
+ assertEquals("Method is required.", e.getMessage());
+ }
+ builder.setHttpMethod(methodName);
+ builder.build().start();
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("Put This Data!", callback.mResponseAsString);
+ assertEquals(methodName, callback.mResponseInfo.getAllHeaders().get("echo-method").get(0));
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testBadMethod() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ try {
+ builder.setHttpMethod("bad:method!");
+ builder.build().start();
+ fail("IllegalArgumentException not thrown.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid http method bad:method!", e.getMessage());
+ }
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testBadHeaderName() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ try {
+ builder.addHeader("header:name", "headervalue");
+ builder.build().start();
+ fail("IllegalArgumentException not thrown.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid header header:name=headervalue", e.getMessage());
+ }
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testBadHeaderValue() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ try {
+ builder.addHeader("headername", "bad header\r\nvalue");
+ builder.build().start();
+ fail("IllegalArgumentException not thrown.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid header headername=bad header\r\nvalue", e.getMessage());
+ }
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testAddHeader() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ String headerName = "header-name";
+ String headerValue = "header-value";
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl(headerName),
+ callback, callback.getExecutor(), mTestFramework.mCronetEngine);
+ builder.addHeader(headerName, headerValue);
+ builder.setHttpMethod("GET");
+ builder.build().start();
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals(headerValue, callback.mResponseAsString);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testMultiRequestHeaders() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ String headerName = "header-name";
+ String headerValue1 = "header-value1";
+ String headerValue2 = "header-value2";
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoAllHeadersUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ builder.addHeader(headerName, headerValue1);
+ builder.addHeader(headerName, headerValue2);
+ builder.setHttpMethod("GET");
+ builder.build().start();
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ String headers = callback.mResponseAsString;
+ Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n");
+ Matcher matcher = pattern.matcher(headers);
+ List<String> actualValues = new ArrayList<String>();
+ while (matcher.find()) {
+ actualValues.add(matcher.group(1));
+ }
+ assertEquals(1, actualValues.size());
+ assertEquals("header-value2", actualValues.get(0));
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testEchoTrailers() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ String headerName = "header-name";
+ String headerValue = "header-value";
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoTrailersUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ builder.addHeader(headerName, headerValue);
+ builder.setHttpMethod("GET");
+ builder.build().start();
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertNotNull(callback.mTrailers);
+ assertEquals(headerValue, callback.mTrailers.getAsMap().get("echo-header-name").get(0));
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testCustomUserAgent() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ String userAgentName = "User-Agent";
+ String userAgentValue = "User-Agent-Value";
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl(userAgentName),
+ callback, callback.getExecutor(), mTestFramework.mCronetEngine);
+ builder.setHttpMethod("GET");
+ builder.addHeader(userAgentName, userAgentValue);
+ builder.build().start();
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals(userAgentValue, callback.mResponseAsString);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testEchoStream() throws Exception {
+ String url = Http2TestServer.getEchoStreamUrl();
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ String[] testData = {"Test String", makeLongString("1234567890", 50000), "woot!"};
+ StringBuilder stringData = new StringBuilder();
+ for (String writeData : testData) {
+ callback.addWriteData(writeData.getBytes());
+ stringData.append(writeData);
+ }
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .addHeader("foo", "Value with Spaces")
+ .addHeader("Content-Type", "zebra")
+ .build();
+ stream.start();
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals(stringData.toString(), callback.mResponseAsString);
+ assertEquals(
+ "Value with Spaces", callback.mResponseInfo.getAllHeaders().get("echo-foo").get(0));
+ assertEquals(
+ "zebra", callback.mResponseInfo.getAllHeaders().get("echo-content-type").get(0));
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testEchoStreamEmptyWrite() throws Exception {
+ String url = Http2TestServer.getEchoStreamUrl();
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.addWriteData(new byte[0]);
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .build();
+ stream.start();
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("", callback.mResponseAsString);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testEchoStreamStepByStep() throws Exception {
+ String url = Http2TestServer.getEchoStreamUrl();
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.setAutoAdvance(false);
+ String[] testData = {"a", "bb", "ccc", "Test String", "1234567890", "woot!"};
+ StringBuilder stringData = new StringBuilder();
+ for (String writeData : testData) {
+ callback.addWriteData(writeData.getBytes());
+ stringData.append(writeData);
+ }
+ // Create stream.
+ BidirectionalStream stream =
+ new BidirectionalStream.Builder(url, callback, callback.getExecutor(),
+ mTestFramework.mCronetEngine)
+ .build();
+ stream.start();
+ callback.waitForNextWriteStep();
+ callback.waitForNextReadStep();
+
+ for (String expected : testData) {
+ // Write next chunk of test data.
+ callback.startNextWrite(stream);
+ callback.waitForNextWriteStep();
+
+ // Read next chunk of test data.
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(100);
+ callback.startNextRead(stream, readBuffer);
+ callback.waitForNextReadStep();
+ assertEquals(expected.length(), readBuffer.position());
+ assertFalse(stream.isDone());
+ }
+
+ callback.setAutoAdvance(true);
+ callback.startNextRead(stream);
+ callback.blockForDone();
+ assertTrue(stream.isDone());
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals(stringData.toString(), callback.mResponseAsString);
+ }
+
+ /**
+ * Checks that the buffer is updated correctly, when starting at an offset.
+ */
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testSimpleGetBufferUpdates() throws Exception {
xunjieli 2016/01/22 16:12:19 Suggest: in this test or another test, test that R
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.setAutoAdvance(false);
+ // Since the method is "GET", the expected response body is also "GET".
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ BidirectionalStream stream = builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.waitForNextReadStep();
+
+ assertEquals(null, callback.mError);
+ assertFalse(callback.isDone());
+ assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_STARTED,
+ callback.mResponseStep);
+
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
+ readBuffer.put("FOR".getBytes());
+ assertEquals(3, readBuffer.position());
+
+ // Read first two characters of the response ("GE"). It's theoretically
+ // possible to need one read per character, though in practice,
+ // shouldn't happen.
+ while (callback.mResponseAsString.length() < 2) {
+ assertFalse(callback.isDone());
+ callback.startNextRead(stream, readBuffer);
+ callback.waitForNextReadStep();
+ }
+
+ // Make sure the two characters were read.
+ assertEquals("GE", callback.mResponseAsString);
+
+ // Check the contents of the entire buffer. The first 3 characters
+ // should not have been changed, and the last two should be the first
+ // two characters from the response.
+ assertEquals("FORGE", bufferContentsToString(readBuffer, 0, 5));
+ // The limit and position should be 5.
+ assertEquals(5, readBuffer.limit());
+ assertEquals(5, readBuffer.position());
+
+ assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
+
+ // Start reading from position 3. Since the only remaining character
+ // from the response is a "T", when the read completes, the buffer
+ // should contain "FORTE", with a position() of 4 and a limit() of 5.
+ readBuffer.position(3);
+ callback.startNextRead(stream, readBuffer);
+ callback.waitForNextReadStep();
+
+ // Make sure all three characters of the response have now been read.
+ assertEquals("GET", callback.mResponseAsString);
+
+ // Check the entire contents of the buffer. Only the third character
+ // should have been modified.
+ assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5));
+
+ // Make sure position and limit were updated correctly.
+ assertEquals(4, readBuffer.position());
+ assertEquals(5, readBuffer.limit());
+
+ assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
+
+ // One more read attempt. The request should complete.
+ readBuffer.position(1);
+ readBuffer.limit(5);
+ callback.startNextRead(stream, readBuffer);
+ callback.waitForNextReadStep();
+
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("GET", callback.mResponseAsString);
+ checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodUrl(), 200, "");
+
+ // Check that buffer contents were not modified.
+ assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5));
+
+ // Position should not have been modified, since nothing was read.
+ assertEquals(1, readBuffer.position());
+ // Limit should be unchanged as always.
+ assertEquals(5, readBuffer.limit());
+
+ assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep);
+
+ // Make sure there are no other pending messages, which would trigger
+ // asserts in TestBidirectionalCallback.
+ testSimpleGet();
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testBadBuffers() throws Exception {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.setAutoAdvance(false);
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ BidirectionalStream stream = builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.waitForNextReadStep();
+
+ assertEquals(null, callback.mError);
+ assertFalse(callback.isDone());
+ assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_STARTED,
+ callback.mResponseStep);
+
+ // Try to read using a full buffer.
+ try {
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(4);
+ readBuffer.put("full".getBytes());
+ stream.read(readBuffer);
+ fail("Exception not thrown");
+ } catch (IllegalArgumentException e) {
+ assertEquals("ByteBuffer is already full.", e.getMessage());
+ }
+
+ // Try to read using a non-direct buffer.
+ try {
+ ByteBuffer readBuffer = ByteBuffer.allocate(5);
+ stream.read(readBuffer);
+ fail("Exception not thrown");
+ } catch (Exception e) {
+ assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage());
+ }
+
+ // Finish the stream with a direct ByteBuffer.
+ callback.setAutoAdvance(true);
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
+ stream.read(readBuffer);
+ callback.blockForDone();
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("GET", callback.mResponseAsString);
+ }
+
+ private void throwOrCancel(FailureType failureType, ResponseStep failureStep,
+ boolean expectResponseInfo, boolean expectError) {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.setFailure(failureType, failureStep);
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ BidirectionalStream stream = builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.blockForDone();
+ assertEquals(callback.mResponseStep, failureStep);
+ assertTrue(stream.isDone());
+ assertEquals(expectResponseInfo, callback.mResponseInfo != null);
+ assertEquals(expectError, callback.mError != null);
+ assertEquals(expectError, callback.mOnErrorCalled);
+ assertEquals(failureType == FailureType.CANCEL_SYNC
+ || failureType == FailureType.CANCEL_ASYNC
+ || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE,
+ callback.mOnCanceledCalled);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testFailures() throws Exception {
+ throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_SENT, false, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_SENT, false, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_REQUEST_HEADERS_SENT,
+ false, false);
+ throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SENT, false, true);
+
+ throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED, true, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RESPONSE_STARTED,
+ true, false);
+ throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, true);
+
+ throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, true, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED, true, false);
+ throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_READ_COMPLETED, true,
+ false);
+ throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, true, true);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testThrowOnSucceeded() {
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+ callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED);
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ BidirectionalStream stream = builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.blockForDone();
+ assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED);
+ assertTrue(stream.isDone());
+ assertNotNull(callback.mResponseInfo);
+ // Check that error thrown from 'onSucceeded' callback is not reported.
+ assertNull(callback.mError);
+ assertFalse(callback.mOnErrorCalled);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testExecutorShutdown() {
xunjieli 2016/01/22 16:12:18 Suggest renaming this test. Maybe testStreamDestro
mef 2016/01/25 18:11:25 This test verifies that stream is destroyed even i
+ TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+
+ callback.setAutoAdvance(false);
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ CronetBidirectionalStream stream =
+ (CronetBidirectionalStream) builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.waitForNextReadStep();
+ assertFalse(callback.isDone());
+ assertFalse(stream.isDone());
+
+ final ConditionVariable requestDestroyed = new ConditionVariable(false);
xunjieli 2016/01/22 16:12:19 suggest s/requestDestroyed/streamDestroyed.
mef 2016/01/25 18:11:25 Done.
+ stream.setOnDestroyedCallbackForTesting(new Runnable() {
+ @Override
+ public void run() {
+ requestDestroyed.open();
+ }
+ });
+
+ // Shut down the executor, so posting the task will throw an exception.
+ callback.shutdownExecutor();
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
+ stream.read(readBuffer);
+ // Callback will never be called again because executor is shut down,
+ // but stream will be destroyed from network thread.
+ requestDestroyed.block();
+
+ assertFalse(callback.isDone());
+ assertTrue(stream.isDone());
+ }
+
+ /**
+ * Callback that shuts down the engine when the stream has succeeded
+ * or failed.
+ */
+ private class ShutdownTestBidirectionalStreamCallback extends TestBidirectionalStreamCallback {
+ @Override
+ public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info) {
+ mTestFramework.mCronetEngine.shutdown();
+ // Clear mCronetEngine so it doesn't get shutdown second time in tearDown().
xunjieli 2016/01/22 16:12:19 nit: s/shutdown/shut down. shutdown happens to be
mef 2016/01/25 18:11:25 Done.
+ mTestFramework.mCronetEngine = null;
+ super.onSucceeded(stream, info);
+ }
+
+ @Override
+ public void onFailed(
+ BidirectionalStream stream, UrlResponseInfo info, CronetException error) {
+ mTestFramework.mCronetEngine.shutdown();
+ // Clear mCronetEngine so it doesn't get shutdown second time in tearDown().
+ mTestFramework.mCronetEngine = null;
+ super.onFailed(stream, info, error);
+ }
+
+ @Override
+ public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {
+ mTestFramework.mCronetEngine.shutdown();
+ // Clear mCronetEngine so it doesn't get shutdown second time in tearDown().
+ mTestFramework.mCronetEngine = null;
+ super.onCanceled(stream, info);
+ }
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testShutdown() throws Exception {
xunjieli 2016/01/22 16:12:19 Hard to see the distinction between this and testE
mef 2016/01/25 18:11:25 Actually, executor CAN be shutdown, but CronetEngi
+ TestBidirectionalStreamCallback callback = new ShutdownTestBidirectionalStreamCallback();
+ // Block callback when response starts to verify that shutdown fails
+ // if there are active stream.
+ callback.setAutoAdvance(false);
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ CronetBidirectionalStream stream =
+ (CronetBidirectionalStream) builder.setHttpMethod("GET").build();
+ stream.start();
+ try {
+ mTestFramework.mCronetEngine.shutdown();
+ fail("Should throw an exception");
+ } catch (Exception e) {
+ assertEquals("Cannot shutdown with active requests.", e.getMessage());
+ }
+
+ callback.waitForNextReadStep();
+ assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
+ try {
+ mTestFramework.mCronetEngine.shutdown();
+ fail("Should throw an exception");
+ } catch (Exception e) {
+ assertEquals("Cannot shutdown with active requests.", e.getMessage());
+ }
+ callback.startNextRead(stream);
+
+ callback.waitForNextReadStep();
+ assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
+ try {
+ mTestFramework.mCronetEngine.shutdown();
+ fail("Should throw an exception");
+ } catch (Exception e) {
+ assertEquals("Cannot shutdown with active requests.", e.getMessage());
+ }
+
+ // May not have read all the data, in theory. Just enable auto-advance
+ // and finish the request.
+ callback.setAutoAdvance(true);
+ callback.startNextRead(stream);
+ callback.blockForDone();
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testShutdownAfterError() throws Exception {
xunjieli 2016/01/22 16:12:19 Suggest adding a documentation to this test. It's
mef 2016/01/25 18:11:25 Done.
+ TestBidirectionalStreamCallback callback = new ShutdownTestBidirectionalStreamCallback();
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ CronetBidirectionalStream stream =
+ (CronetBidirectionalStream) builder.setHttpMethod("GET").build();
+ stream.start();
+ callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED);
+ callback.blockForDone();
+ assertTrue(callback.mOnErrorCalled);
+ }
+
+ @SmallTest
+ @Feature({"Cronet"})
+ @OnlyRunNativeCronet
+ public void testShutdownAfterCancel() throws Exception {
+ TestBidirectionalStreamCallback callback = new ShutdownTestBidirectionalStreamCallback();
+ BidirectionalStream.Builder builder =
+ new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl(), callback,
+ callback.getExecutor(), mTestFramework.mCronetEngine);
+ CronetBidirectionalStream stream =
+ (CronetBidirectionalStream) builder.setHttpMethod("GET").build();
+
+ // Block callback when response starts to verify that shutdown fails
+ // if there are active requests.
+ callback.setAutoAdvance(false);
+ stream.start();
+ try {
+ mTestFramework.mCronetEngine.shutdown();
xunjieli 2016/01/22 16:12:19 This test is confusing. The callback class calls s
mef 2016/01/25 18:11:25 Done.
+ fail("Should throw an exception");
+ } catch (Exception e) {
+ assertEquals("Cannot shutdown with active requests.", e.getMessage());
+ }
+ callback.waitForNextReadStep();
+ assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
+ stream.cancel();
+ }
+
+ // Returns the contents of byteBuffer, from its position() to its limit(),
+ // as a String. Does not modify byteBuffer's position().
+ private static String bufferContentsToString(ByteBuffer byteBuffer, int start, int end) {
+ // Use a duplicate to avoid modifying byteBuffer.
+ ByteBuffer duplicate = byteBuffer.duplicate();
+ duplicate.position(start);
+ duplicate.limit(end);
+ byte[] contents = new byte[duplicate.remaining()];
+ duplicate.get(contents);
+ return new String(contents);
+ }
}

Powered by Google App Engine
This is Rietveld 408576698