Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.net; | 5 package org.chromium.net; |
| 6 | 6 |
| 7 import android.os.ConditionVariable; | |
| 7 import android.test.suitebuilder.annotation.SmallTest; | 8 import android.test.suitebuilder.annotation.SmallTest; |
| 8 | 9 |
| 9 import org.chromium.base.test.util.Feature; | 10 import org.chromium.base.test.util.Feature; |
| 11 import org.chromium.net.TestBidirectionalStreamCallback.FailureType; | |
| 12 import org.chromium.net.TestBidirectionalStreamCallback.ResponseStep; | |
| 10 | 13 |
| 11 import java.nio.ByteBuffer; | 14 import java.nio.ByteBuffer; |
| 12 import java.util.concurrent.Executor; | 15 import java.util.ArrayList; |
| 13 import java.util.concurrent.ExecutorService; | 16 import java.util.List; |
| 14 import java.util.concurrent.Executors; | 17 import java.util.regex.Matcher; |
| 15 import java.util.concurrent.ThreadFactory; | 18 import java.util.regex.Pattern; |
| 16 | |
| 17 /** | 19 /** |
| 18 * Test functionality of BidirectionalStream interface. | 20 * Test functionality of BidirectionalStream interface. |
| 19 */ | 21 */ |
| 20 public class BidirectionalStreamTest extends CronetTestBase { | 22 public class BidirectionalStreamTest extends CronetTestBase { |
| 23 private static final String CERT_USED = "quic_test.example.com.crt"; | |
| 24 private static final String KEY_USED = "quic_test.example.com.key"; | |
| 25 private static final String[] CERTS_USED = {CERT_USED}; | |
| 26 | |
| 21 private CronetTestFramework mTestFramework; | 27 private CronetTestFramework mTestFramework; |
| 28 // URL used for base tests. | |
| 29 private static final String TEST_URL = "https://127.0.0.1:8443"; | |
| 22 | 30 |
| 23 @Override | 31 @Override |
| 24 protected void setUp() throws Exception { | 32 protected void setUp() throws Exception { |
| 25 super.setUp(); | 33 super.setUp(); |
| 26 mTestFramework = startCronetTestFramework(); | 34 // Load library first to create MockCertVerifier. |
| 35 System.loadLibrary("cronet_tests"); | |
| 36 | |
| 37 CronetEngine.Builder builder = new CronetEngine.Builder(getContext()); | |
| 38 builder.setMockCertVerifierForTesting(MockCertVerifier.createMockCertVer ifier(CERTS_USED)); | |
| 39 | |
| 40 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n ull, builder); | |
| 27 assertTrue(NativeTestServer.startNativeTestServer(getContext())); | 41 assertTrue(NativeTestServer.startNativeTestServer(getContext())); |
| 42 assertTrue(Http2TestServer.startHttp2TestServer(getContext(), CERT_USED, KEY_USED)); | |
|
pauljensen
2016/01/04 19:56:00
Hmm so will Andrei's work add Http2TestServer?
mef
2016/01/04 22:27:08
It is added in my CL https://codereview.chromium.o
| |
| 28 // Add url interceptors after native application context is initialized. | 43 // Add url interceptors after native application context is initialized. |
| 29 MockUrlRequestJobFactory.setUp(); | 44 MockUrlRequestJobFactory.setUp(); |
| 30 } | 45 } |
| 31 | 46 |
| 32 @Override | 47 @Override |
| 33 protected void tearDown() throws Exception { | 48 protected void tearDown() throws Exception { |
| 49 Http2TestServer.shutdownHttp2TestServer(); | |
| 34 NativeTestServer.shutdownNativeTestServer(); | 50 NativeTestServer.shutdownNativeTestServer(); |
| 35 mTestFramework.mCronetEngine.shutdown(); | 51 if (mTestFramework.mCronetEngine != null) mTestFramework.mCronetEngine.s hutdown(); |
| 36 super.tearDown(); | 52 super.tearDown(); |
| 37 } | 53 } |
| 38 | 54 |
| 39 private class TestBidirectionalStreamCallback extends BidirectionalStream.Ca llback { | 55 private TestBidirectionalStreamCallback startAndWaitForComplete(String url) throws Exception { |
| 40 // Executor Service for Cronet callbacks. | 56 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); |
| 41 private final ExecutorService mExecutorService = | |
| 42 Executors.newSingleThreadExecutor(new ExecutorThreadFactory()); | |
| 43 private Thread mExecutorThread; | |
| 44 | 57 |
| 45 private class ExecutorThreadFactory implements ThreadFactory { | 58 // Create stream. |
| 46 public Thread newThread(Runnable r) { | 59 BidirectionalStream stream = |
| 47 mExecutorThread = new Thread(r); | 60 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(), |
| 48 return mExecutorThread; | 61 mTestFramework.mCronetEngine) |
| 49 } | 62 .setHttpMethod("GET") |
| 63 .build(); | |
| 64 stream.start(); | |
| 65 callback.blockForDone(); | |
| 66 assertTrue(stream.isDone()); | |
| 67 return callback; | |
| 68 } | |
| 69 | |
| 70 private void checkResponseInfo(UrlResponseInfo responseInfo, String expected Url, | |
| 71 int expectedHttpStatusCode, String expectedHttpStatusText) { | |
| 72 assertEquals(expectedUrl, responseInfo.getUrl()); | |
| 73 assertEquals( | |
| 74 expectedUrl, responseInfo.getUrlChain().get(responseInfo.getUrlC hain().size() - 1)); | |
| 75 assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode()); | |
| 76 assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText()); | |
| 77 assertFalse(responseInfo.wasCached()); | |
| 78 assertTrue(responseInfo.toString().length() > 0); | |
| 79 } | |
| 80 | |
| 81 private static String makeLongString(String base, int repetition) { | |
| 82 StringBuilder builder = new StringBuilder(base.length() * repetition); | |
| 83 for (int i = 0; i < repetition; ++i) { | |
| 84 builder.append(i); | |
| 85 builder.append(base); | |
| 50 } | 86 } |
| 51 | 87 return builder.toString(); |
| 52 @Override | |
| 53 public void onRequestHeadersSent(BidirectionalStream stream) {} | |
| 54 | |
| 55 @Override | |
| 56 public void onResponseHeadersReceived(BidirectionalStream stream, UrlRes ponseInfo info) {} | |
| 57 | |
| 58 @Override | |
| 59 public void onReadCompleted( | |
| 60 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf fer) {} | |
| 61 | |
| 62 @Override | |
| 63 public void onWriteCompleted( | |
| 64 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf fer) {} | |
| 65 | |
| 66 @Override | |
| 67 public void onResponseTrailersReceived(BidirectionalStream stream, UrlRe sponseInfo info, | |
| 68 UrlResponseInfo.HeaderBlock trailers) {} | |
| 69 | |
| 70 @Override | |
| 71 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) {} | |
| 72 | |
| 73 @Override | |
| 74 public void onFailed( | |
| 75 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) {} | |
| 76 | |
| 77 @Override | |
| 78 public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {} | |
| 79 | |
| 80 Executor getExecutor() { | |
| 81 return mExecutorService; | |
| 82 } | |
| 83 } | 88 } |
| 84 | 89 |
| 85 @SmallTest | 90 @SmallTest |
| 86 @Feature({"Cronet"}) | 91 @Feature({"Cronet"}) |
| 87 public void testBuilderChecks() throws Exception { | 92 public void testBuilderChecks() throws Exception { |
| 88 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | 93 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); |
| 89 try { | 94 try { |
| 90 new BidirectionalStream.Builder( | 95 new BidirectionalStream.Builder( |
| 91 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | 96 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine); |
| 92 fail("URL not null-checked"); | 97 fail("URL not null-checked"); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 111 new BidirectionalStream.Builder( | 116 new BidirectionalStream.Builder( |
| 112 NativeTestServer.getRedirectURL(), callback, callback.getExe cutor(), null); | 117 NativeTestServer.getRedirectURL(), callback, callback.getExe cutor(), null); |
| 113 fail("CronetEngine not null-checked"); | 118 fail("CronetEngine not null-checked"); |
| 114 } catch (NullPointerException e) { | 119 } catch (NullPointerException e) { |
| 115 assertEquals("CronetEngine is required.", e.getMessage()); | 120 assertEquals("CronetEngine is required.", e.getMessage()); |
| 116 } | 121 } |
| 117 // Verify successful creation doesn't throw. | 122 // Verify successful creation doesn't throw. |
| 118 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb ack, | 123 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb ack, |
| 119 callback.getExecutor(), mTestFramework.mCronetEngine); | 124 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 120 } | 125 } |
| 126 | |
| 127 @SmallTest | |
| 128 @Feature({"Cronet"}) | |
| 129 public void testFailPlainHttp() throws Exception { | |
| 130 String url = NativeTestServer.getEchoMethodURL(); | |
| 131 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url); | |
| 132 assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_ SCHEME", | |
| 133 callback.mError.getMessage()); | |
| 134 } | |
| 135 | |
| 136 @SmallTest | |
| 137 @Feature({"Cronet"}) | |
| 138 public void testSimpleGet() throws Exception { | |
| 139 String url = Http2TestServer.getEchoMethodUrl(); | |
| 140 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url); | |
| 141 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 142 // Default method is 'GET'. | |
| 143 assertEquals("GET", callback.mResponseAsString); | |
| 144 assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s], httpSt atus = 200 , " | |
| 145 + "headers = [:status=200], wasCached = fal se, " | |
| 146 + "negotiatedProtocol = h2, proxyServer= nu ll, " | |
| 147 + "receivedBytesCount = 27", | |
| 148 url, url), | |
| 149 callback.mResponseInfo.toString()); | |
| 150 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
| 151 } | |
| 152 | |
| 153 @SmallTest | |
| 154 @Feature({"Cronet"}) | |
| 155 public void testSimpleHead() throws Exception { | |
| 156 String url = Http2TestServer.getEchoMethodUrl(); | |
| 157 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 158 | |
| 159 // Create stream. | |
| 160 BidirectionalStream stream = | |
| 161 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(), | |
| 162 mTestFramework.mCronetEngine) | |
| 163 .setHttpMethod("HEAD") | |
| 164 .build(); | |
| 165 stream.start(); | |
| 166 callback.blockForDone(); | |
| 167 assertTrue(stream.isDone()); | |
| 168 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 169 assertEquals("HEAD", callback.mResponseAsString); | |
| 170 assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s], httpSt atus = 200 , " | |
| 171 + "headers = [:status=200], wasCached = fal se, " | |
| 172 + "negotiatedProtocol = h2, proxyServer= nu ll, " | |
| 173 + "receivedBytesCount = 28", | |
| 174 url, url), | |
| 175 callback.mResponseInfo.toString()); | |
| 176 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
| 177 } | |
| 178 | |
| 179 @SmallTest | |
| 180 @Feature({"Cronet"}) | |
| 181 public void testSimplePost() throws Exception { | |
| 182 String url = Http2TestServer.getBaseUrl(); | |
| 183 mTestFramework.startNetLog(); | |
| 184 | |
| 185 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 186 callback.addWriteData("Test String".getBytes()); | |
| 187 callback.addWriteData("1234567890".getBytes()); | |
| 188 callback.addWriteData("woot!".getBytes()); | |
| 189 | |
| 190 // Create stream. | |
| 191 BidirectionalStream stream = | |
| 192 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(), | |
| 193 mTestFramework.mCronetEngine) | |
| 194 .addHeader("foo", "bar") | |
| 195 .addHeader("Content-Type", "zebra") | |
| 196 .build(); | |
| 197 stream.start(); | |
| 198 callback.blockForDone(); | |
| 199 assertTrue(stream.isDone()); | |
| 200 | |
| 201 mTestFramework.stopNetLog(); | |
| 202 | |
| 203 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 204 assertEquals("woot!", callback.mResponseAsString); | |
| 205 } | |
| 206 | |
| 207 @SmallTest | |
| 208 @Feature({"Cronet"}) | |
| 209 public void testSetHttpMethod() throws Exception { | |
| 210 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 211 callback.addWriteData("Put This Data!".getBytes()); | |
| 212 | |
| 213 String methodName = "PUT"; | |
| 214 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( | |
| 215 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | |
| 216 // Try to set 'null' method. | |
| 217 try { | |
| 218 builder.setHttpMethod(null); | |
| 219 fail("Exception not thrown"); | |
| 220 } catch (NullPointerException e) { | |
| 221 assertEquals("Method is required.", e.getMessage()); | |
| 222 } | |
| 223 | |
| 224 builder.setHttpMethod(methodName); | |
| 225 builder.build().start(); | |
| 226 callback.blockForDone(); | |
| 227 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 228 assertEquals("Put This Data!", callback.mResponseAsString); | |
| 229 } | |
| 230 | |
| 231 @SmallTest | |
| 232 @Feature({"Cronet"}) | |
| 233 public void testBadMethod() throws Exception { | |
| 234 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 235 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( | |
| 236 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | |
| 237 try { | |
| 238 builder.setHttpMethod("bad:method!"); | |
| 239 builder.build().start(); | |
| 240 fail("IllegalArgumentException not thrown."); | |
| 241 } catch (IllegalArgumentException e) { | |
| 242 assertEquals("Invalid http method bad:method!", e.getMessage()); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 @SmallTest | |
| 247 @Feature({"Cronet"}) | |
| 248 public void testBadHeaderName() throws Exception { | |
| 249 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 250 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( | |
| 251 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | |
| 252 try { | |
| 253 builder.addHeader("header:name", "headervalue"); | |
| 254 builder.build().start(); | |
| 255 fail("IllegalArgumentException not thrown."); | |
| 256 } catch (IllegalArgumentException e) { | |
| 257 assertEquals("Invalid header header:name=headervalue", e.getMessage( )); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 @SmallTest | |
| 262 @Feature({"Cronet"}) | |
| 263 public void testBadHeaderValue() throws Exception { | |
| 264 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 265 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( | |
| 266 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | |
| 267 try { | |
| 268 builder.addHeader("headername", "bad header\r\nvalue"); | |
| 269 builder.build().start(); | |
| 270 fail("IllegalArgumentException not thrown."); | |
| 271 } catch (IllegalArgumentException e) { | |
| 272 assertEquals("Invalid header headername=bad header\r\nvalue", e.getM essage()); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 @SmallTest | |
| 277 @Feature({"Cronet"}) | |
| 278 public void testAddHeader() throws Exception { | |
| 279 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 280 String headerName = "header-name"; | |
| 281 String headerValue = "header-value"; | |
| 282 BidirectionalStream.Builder builder = | |
| 283 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (headerName), | |
| 284 callback, callback.getExecutor(), mTestFramework.mCronet Engine); | |
| 285 | |
| 286 builder.addHeader(headerName, headerValue); | |
| 287 builder.setHttpMethod("GET"); | |
| 288 builder.build().start(); | |
| 289 callback.blockForDone(); | |
| 290 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 291 assertEquals(headerValue, callback.mResponseAsString); | |
| 292 } | |
| 293 | |
| 294 @SmallTest | |
| 295 @Feature({"Cronet"}) | |
| 296 public void testMultiRequestHeaders() throws Exception { | |
| 297 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 298 String headerName = "header-name"; | |
| 299 String headerValue1 = "header-value1"; | |
| 300 String headerValue2 = "header-value2"; | |
| 301 BidirectionalStream.Builder builder = | |
| 302 new BidirectionalStream.Builder(Http2TestServer.getEchoAllHeader sUrl(), callback, | |
| 303 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 304 builder.addHeader(headerName, headerValue1); | |
| 305 builder.addHeader(headerName, headerValue2); | |
| 306 builder.setHttpMethod("GET"); | |
| 307 builder.build().start(); | |
| 308 callback.blockForDone(); | |
| 309 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 310 String headers = callback.mResponseAsString; | |
| 311 Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n"); | |
| 312 Matcher matcher = pattern.matcher(headers); | |
| 313 List<String> actualValues = new ArrayList<String>(); | |
| 314 while (matcher.find()) { | |
| 315 actualValues.add(matcher.group(1)); | |
| 316 } | |
| 317 assertEquals(1, actualValues.size()); | |
| 318 assertEquals("header-value2", actualValues.get(0)); | |
| 319 } | |
| 320 | |
| 321 @SmallTest | |
| 322 @Feature({"Cronet"}) | |
| 323 public void testEchoTrailers() throws Exception { | |
| 324 mTestFramework.startNetLog(); | |
| 325 | |
| 326 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 327 String headerName = "header-name"; | |
| 328 String headerValue = "header-value"; | |
| 329 BidirectionalStream.Builder builder = | |
| 330 new BidirectionalStream.Builder(Http2TestServer.getEchoTrailersU rl(), callback, | |
| 331 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 332 builder.addHeader(headerName, headerValue); | |
| 333 builder.setHttpMethod("GET"); | |
| 334 builder.build().start(); | |
| 335 callback.blockForDone(); | |
| 336 mTestFramework.stopNetLog(); | |
| 337 | |
| 338 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 339 assertNotNull(callback.mTrailers); | |
| 340 assertEquals(headerValue, callback.mTrailers.getAsMap().get(headerName). get(0)); | |
| 341 } | |
| 342 | |
| 343 @SmallTest | |
| 344 @Feature({"Cronet"}) | |
| 345 public void testCustomUserAgent() throws Exception { | |
| 346 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 347 String userAgentName = "User-Agent"; | |
| 348 String userAgentValue = "User-Agent-Value"; | |
| 349 BidirectionalStream.Builder builder = | |
| 350 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (userAgentName), | |
| 351 callback, callback.getExecutor(), mTestFramework.mCronet Engine); | |
| 352 builder.setHttpMethod("GET"); | |
| 353 builder.addHeader(userAgentName, userAgentValue); | |
| 354 builder.build().start(); | |
| 355 callback.blockForDone(); | |
| 356 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 357 assertEquals(userAgentValue, callback.mResponseAsString); | |
| 358 } | |
| 359 | |
| 360 @SmallTest | |
| 361 @Feature({"Cronet"}) | |
| 362 public void testEchoStream() throws Exception { | |
| 363 String url = Http2TestServer.getEchoStreamUrl(); | |
| 364 mTestFramework.startNetLog(); | |
| 365 | |
| 366 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 367 String[] testData = {"Test String", makeLongString("1234567890", 50000), "woot!"}; | |
| 368 StringBuilder stringData = new StringBuilder(); | |
| 369 for (String writeData : testData) { | |
| 370 callback.addWriteData(writeData.getBytes()); | |
| 371 stringData.append(writeData); | |
| 372 } | |
| 373 | |
| 374 // Create stream. | |
| 375 BidirectionalStream stream = | |
| 376 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(), | |
| 377 mTestFramework.mCronetEngine) | |
| 378 .addHeader("foo", "Value with Spaces") | |
| 379 .addHeader("Content-Type", "zebra") | |
| 380 .build(); | |
| 381 stream.start(); | |
| 382 callback.blockForDone(); | |
| 383 assertTrue(stream.isDone()); | |
| 384 | |
| 385 mTestFramework.stopNetLog(); | |
| 386 | |
| 387 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 388 assertEquals(stringData.toString(), callback.mResponseAsString); | |
| 389 assertEquals("Value with Spaces", callback.mResponseInfo.getAllHeaders() .get("foo").get(0)); | |
| 390 assertEquals("zebra", callback.mResponseInfo.getAllHeaders().get("Conten t-Type").get(0)); | |
| 391 } | |
| 392 | |
| 393 /** | |
| 394 * Checks that the buffer is updated correctly, when starting at an offset. | |
| 395 */ | |
| 396 @SmallTest | |
| 397 @Feature({"Cronet"}) | |
| 398 public void testSimpleGetBufferUpdates() throws Exception { | |
| 399 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 400 callback.setAutoAdvance(false); | |
| 401 // Since themethod is "GET", the expected response body is also "GET". | |
| 402 BidirectionalStream.Builder builder = | |
| 403 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 404 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 405 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
| 406 stream.start(); | |
| 407 callback.waitForNextReadStep(); | |
| 408 | |
| 409 assertEquals(null, callback.mError); | |
| 410 assertFalse(callback.isDone()); | |
| 411 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED, | |
| 412 callback.mResponseStep); | |
| 413 | |
| 414 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
| 415 readBuffer.put("FOR".getBytes()); | |
| 416 assertEquals(3, readBuffer.position()); | |
| 417 | |
| 418 // Read first two characters of the response ("GE"). It's theoretically | |
| 419 // possible to need one read per character, though in practice, | |
| 420 // shouldn't happen. | |
| 421 while (callback.mResponseAsString.length() < 2) { | |
| 422 assertFalse(callback.isDone()); | |
| 423 callback.startNextRead(stream, readBuffer); | |
| 424 callback.waitForNextReadStep(); | |
| 425 } | |
| 426 | |
| 427 // Make sure the two characters were read. | |
| 428 assertEquals("GE", callback.mResponseAsString); | |
| 429 | |
| 430 // Check the contents of the entire buffer. The first 3 characters | |
| 431 // should not have been changed, and the last two should be the first | |
| 432 // two characters from the response. | |
| 433 assertEquals("FORGE", bufferContentsToString(readBuffer, 0, 5)); | |
| 434 // The limit and position should be 5. | |
| 435 assertEquals(5, readBuffer.limit()); | |
| 436 assertEquals(5, readBuffer.position()); | |
| 437 | |
| 438 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
| 439 | |
| 440 // Start reading from position 3. Since the only remaining character | |
| 441 // from the response is a "T", when the read completes, the buffer | |
| 442 // should contain "FORTE", with a position() of 4 and a limit() of 5. | |
| 443 readBuffer.position(3); | |
| 444 callback.startNextRead(stream, readBuffer); | |
| 445 callback.waitForNextReadStep(); | |
| 446 | |
| 447 // Make sure all three characters of the response have now been read. | |
| 448 assertEquals("GET", callback.mResponseAsString); | |
| 449 | |
| 450 // Check the entire contents of the buffer. Only the third character | |
| 451 // should have been modified. | |
| 452 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); | |
| 453 | |
| 454 // Make sure position and limit were updated correctly. | |
| 455 assertEquals(4, readBuffer.position()); | |
| 456 assertEquals(5, readBuffer.limit()); | |
| 457 | |
| 458 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
| 459 | |
| 460 // One more read attempt. The request should complete. | |
| 461 readBuffer.position(1); | |
| 462 readBuffer.limit(5); | |
| 463 callback.startNextRead(stream, readBuffer); | |
| 464 callback.waitForNextReadStep(); | |
| 465 | |
| 466 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 467 assertEquals("GET", callback.mResponseAsString); | |
| 468 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
| 469 | |
| 470 // Check that buffer contents were not modified. | |
| 471 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); | |
| 472 | |
| 473 // Position should not have been modified, since nothing was read. | |
| 474 assertEquals(1, readBuffer.position()); | |
| 475 // Limit should be unchanged as always. | |
| 476 assertEquals(5, readBuffer.limit()); | |
| 477 | |
| 478 assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep); | |
| 479 | |
| 480 // Make sure there are no other pending messages, which would trigger | |
| 481 // asserts in TestBidirectionalCallback. | |
| 482 testSimpleGet(); | |
| 483 } | |
| 484 | |
| 485 @SmallTest | |
| 486 @Feature({"Cronet"}) | |
| 487 public void testBadBuffers() throws Exception { | |
| 488 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 489 callback.setAutoAdvance(false); | |
| 490 BidirectionalStream.Builder builder = | |
| 491 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 492 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 493 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
| 494 stream.start(); | |
| 495 callback.waitForNextReadStep(); | |
| 496 | |
| 497 assertEquals(null, callback.mError); | |
| 498 assertFalse(callback.isDone()); | |
| 499 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED, | |
| 500 callback.mResponseStep); | |
| 501 | |
| 502 // Try to read using a full buffer. | |
| 503 try { | |
| 504 ByteBuffer readBuffer = ByteBuffer.allocateDirect(4); | |
| 505 readBuffer.put("full".getBytes()); | |
| 506 stream.read(readBuffer); | |
| 507 fail("Exception not thrown"); | |
| 508 } catch (IllegalArgumentException e) { | |
| 509 assertEquals("ByteBuffer is already full.", e.getMessage()); | |
| 510 } | |
| 511 | |
| 512 // Try to read using a non-direct buffer. | |
| 513 try { | |
| 514 ByteBuffer readBuffer = ByteBuffer.allocate(5); | |
| 515 stream.read(readBuffer); | |
| 516 fail("Exception not thrown"); | |
| 517 } catch (Exception e) { | |
| 518 assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage ()); | |
| 519 } | |
| 520 | |
| 521 // Finish the stream with a direct ByteBuffer. | |
| 522 callback.setAutoAdvance(true); | |
| 523 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
| 524 stream.read(readBuffer); | |
| 525 callback.blockForDone(); | |
| 526 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
| 527 assertEquals("GET", callback.mResponseAsString); | |
| 528 } | |
| 529 | |
| 530 private void throwOrCancel(FailureType failureType, ResponseStep failureStep , | |
| 531 boolean expectResponseInfo, boolean expectError) { | |
| 532 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 533 callback.setFailure(failureType, failureStep); | |
| 534 BidirectionalStream.Builder builder = | |
| 535 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 536 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 537 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
| 538 stream.start(); | |
| 539 callback.blockForDone(); | |
| 540 assertEquals(callback.mResponseStep, failureStep); | |
| 541 assertTrue(stream.isDone()); | |
| 542 assertEquals(expectResponseInfo, callback.mResponseInfo != null); | |
| 543 assertEquals(expectError, callback.mError != null); | |
| 544 assertEquals(expectError, callback.mOnErrorCalled); | |
| 545 assertEquals(failureType == FailureType.CANCEL_SYNC | |
| 546 || failureType == FailureType.CANCEL_ASYNC | |
| 547 || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE , | |
| 548 callback.mOnCanceledCalled); | |
| 549 } | |
| 550 | |
| 551 @SmallTest | |
| 552 @Feature({"Cronet"}) | |
| 553 public void testFailures() throws Exception { | |
| 554 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_S ENT, false, false); | |
| 555 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_ SENT, false, false); | |
| 556 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE QUEST_HEADERS_SENT, | |
| 557 false, false); | |
| 558 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SE NT, false, true); | |
| 559 | |
| 560 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, false); | |
| 561 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED , true, false); | |
| 562 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE SPONSE_STARTED, | |
| 563 true, false); | |
| 564 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, true); | |
| 565 | |
| 566 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, t rue, false); | |
| 567 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED, true, false); | |
| 568 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE AD_COMPLETED, true, | |
| 569 false); | |
| 570 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, tr ue, true); | |
| 571 } | |
| 572 | |
| 573 @SmallTest | |
| 574 @Feature({"Cronet"}) | |
| 575 public void testThrowOnSucceeded() { | |
| 576 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 577 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED); | |
| 578 BidirectionalStream.Builder builder = | |
| 579 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 580 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 581 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
| 582 stream.start(); | |
| 583 callback.blockForDone(); | |
| 584 assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED); | |
| 585 assertTrue(stream.isDone()); | |
| 586 assertNotNull(callback.mResponseInfo); | |
| 587 assertNull(callback.mError); | |
| 588 assertFalse(callback.mOnErrorCalled); | |
| 589 } | |
| 590 | |
| 591 @SmallTest | |
| 592 @Feature({"Cronet"}) | |
| 593 public void testExecutorShutdown() { | |
| 594 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
| 595 | |
| 596 callback.setAutoAdvance(false); | |
| 597 BidirectionalStream.Builder builder = | |
| 598 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 599 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 600 CronetBidirectionalStream stream = | |
| 601 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
| 602 stream.start(); | |
| 603 callback.waitForNextReadStep(); | |
| 604 assertFalse(callback.isDone()); | |
| 605 assertFalse(stream.isDone()); | |
| 606 | |
| 607 final ConditionVariable requestDestroyed = new ConditionVariable(false); | |
| 608 stream.setOnDestroyedCallbackForTests(new Runnable() { | |
| 609 @Override | |
| 610 public void run() { | |
| 611 requestDestroyed.open(); | |
| 612 } | |
| 613 }); | |
| 614 | |
| 615 // Shutdown the executor, so posting the task will throw an exception. | |
| 616 callback.shutdownExecutor(); | |
| 617 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
| 618 stream.read(readBuffer); | |
| 619 // Callback will never be called again because executor is shutdown, | |
| 620 // but stream will be destroyed from network thread. | |
| 621 requestDestroyed.block(); | |
| 622 | |
| 623 assertFalse(callback.isDone()); | |
| 624 assertTrue(stream.isDone()); | |
| 625 } | |
| 626 | |
| 627 /** | |
| 628 * Callback that shutdowns the engine when the stream has succeeded | |
| 629 * or failed. | |
| 630 */ | |
| 631 class ShutdownTestBidirectionalStreamCallback extends TestBidirectionalStrea mCallback { | |
| 632 @Override | |
| 633 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) { | |
| 634 mTestFramework.mCronetEngine.shutdown(); | |
| 635 // Clear mCronetEngine so it doesn't get shutdown second time in tea rDown(). | |
| 636 mTestFramework.mCronetEngine = null; | |
| 637 super.onSucceeded(stream, info); | |
| 638 } | |
| 639 | |
| 640 @Override | |
| 641 public void onFailed( | |
| 642 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) { | |
| 643 mTestFramework.mCronetEngine.shutdown(); | |
| 644 // Clear mCronetEngine so it doesn't get shutdown second time in tea rDown(). | |
| 645 mTestFramework.mCronetEngine = null; | |
| 646 super.onFailed(stream, info, error); | |
| 647 } | |
| 648 } | |
| 649 | |
| 650 @SmallTest | |
| 651 @Feature({"Cronet"}) | |
| 652 public void testShutdown() throws Exception { | |
| 653 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
| 654 // Block callback when response starts to verify that shutdown fails | |
| 655 // if there are active stream. | |
| 656 callback.setAutoAdvance(false); | |
| 657 BidirectionalStream.Builder builder = | |
| 658 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 659 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 660 CronetBidirectionalStream stream = | |
| 661 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
| 662 stream.start(); | |
| 663 try { | |
| 664 mTestFramework.mCronetEngine.shutdown(); | |
| 665 fail("Should throw an exception"); | |
| 666 } catch (Exception e) { | |
| 667 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
| 668 } | |
| 669 | |
| 670 callback.waitForNextReadStep(); | |
| 671 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep); | |
| 672 try { | |
| 673 mTestFramework.mCronetEngine.shutdown(); | |
| 674 fail("Should throw an exception"); | |
| 675 } catch (Exception e) { | |
| 676 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
| 677 } | |
| 678 callback.startNextRead(stream); | |
| 679 | |
| 680 callback.waitForNextReadStep(); | |
| 681 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
| 682 try { | |
| 683 mTestFramework.mCronetEngine.shutdown(); | |
| 684 fail("Should throw an exception"); | |
| 685 } catch (Exception e) { | |
| 686 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
| 687 } | |
| 688 | |
| 689 // May not have read all the data, in theory. Just enable auto-advance | |
| 690 // and finish the request. | |
| 691 callback.setAutoAdvance(true); | |
| 692 callback.startNextRead(stream); | |
| 693 callback.blockForDone(); | |
| 694 } | |
| 695 | |
| 696 @SmallTest | |
| 697 @Feature({"Cronet"}) | |
| 698 public void testShutdownAfterError() throws Exception { | |
| 699 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
| 700 BidirectionalStream.Builder builder = | |
| 701 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 702 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 703 CronetBidirectionalStream stream = | |
| 704 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
| 705 stream.start(); | |
| 706 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLET ED); | |
| 707 callback.blockForDone(); | |
| 708 assertTrue(callback.mOnErrorCalled); | |
| 709 } | |
| 710 | |
| 711 @SmallTest | |
| 712 @Feature({"Cronet"}) | |
| 713 public void testShutdownAfterCancel() throws Exception { | |
| 714 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
| 715 BidirectionalStream.Builder builder = | |
| 716 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
| 717 callback.getExecutor(), mTestFramework.mCronetEngine); | |
| 718 CronetBidirectionalStream stream = | |
| 719 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
| 720 | |
| 721 // Block callback when response starts to verify that shutdown fails | |
| 722 // if there are active requests. | |
| 723 callback.setAutoAdvance(false); | |
| 724 stream.start(); | |
| 725 try { | |
| 726 mTestFramework.mCronetEngine.shutdown(); | |
| 727 fail("Should throw an exception"); | |
| 728 } catch (Exception e) { | |
| 729 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
| 730 } | |
| 731 callback.waitForNextReadStep(); | |
| 732 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep); | |
| 733 stream.cancel(); | |
| 734 } | |
| 735 | |
| 736 // Returns the contents of byteBuffer, from its position() to its limit(), | |
| 737 // as a String. Does not modify byteBuffer's position(). | |
| 738 private String bufferContentsToString(ByteBuffer byteBuffer, int start, int end) { | |
| 739 // Use a duplicate to avoid modifying byteBuffer. | |
| 740 ByteBuffer duplicate = byteBuffer.duplicate(); | |
| 741 duplicate.position(start); | |
| 742 duplicate.limit(end); | |
| 743 byte[] contents = new byte[duplicate.remaining()]; | |
| 744 duplicate.get(contents); | |
| 745 return new String(contents); | |
| 746 } | |
| 121 } | 747 } |
| OLD | NEW |