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 // Empty array of CERTS chages MockCertVerifier default to net::OK. |
| 24 private static final String[] CERTS_USED = {}; |
21 private CronetTestFramework mTestFramework; | 25 private CronetTestFramework mTestFramework; |
| 26 // URL used for base tests. |
| 27 private static final String TEST_URL = "https://127.0.0.1:8443"; |
22 | 28 |
23 @Override | 29 @Override |
24 protected void setUp() throws Exception { | 30 protected void setUp() throws Exception { |
25 super.setUp(); | 31 super.setUp(); |
26 mTestFramework = startCronetTestFramework(); | 32 // Load library first to create MockCertVerifier. |
| 33 System.loadLibrary("cronet_tests"); |
| 34 |
| 35 CronetEngine.Builder builder = new CronetEngine.Builder(getContext()); |
| 36 |
| 37 builder.setMockCertVerifierForTesting(MockCertVerifier.createMockCertVer
ifier(CERTS_USED)); |
| 38 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n
ull, builder); |
27 assertTrue(NativeTestServer.startNativeTestServer(getContext())); | 39 assertTrue(NativeTestServer.startNativeTestServer(getContext())); |
28 // Add url interceptors after native application context is initialized. | 40 // Add url interceptors after native application context is initialized. |
29 MockUrlRequestJobFactory.setUp(); | 41 MockUrlRequestJobFactory.setUp(); |
30 } | 42 } |
31 | 43 |
32 @Override | 44 @Override |
33 protected void tearDown() throws Exception { | 45 protected void tearDown() throws Exception { |
34 NativeTestServer.shutdownNativeTestServer(); | 46 NativeTestServer.shutdownNativeTestServer(); |
35 mTestFramework.mCronetEngine.shutdown(); | 47 mTestFramework.mCronetEngine.shutdown(); |
36 super.tearDown(); | 48 super.tearDown(); |
37 } | 49 } |
38 | 50 |
39 private class TestBidirectionalStreamCallback extends BidirectionalStream.Ca
llback { | 51 static class TestHttp2Server { |
40 // Executor Service for Cronet callbacks. | 52 static String getBaseUrl() { |
41 private final ExecutorService mExecutorService = | 53 return "https://localhost:8443/"; |
42 Executors.newSingleThreadExecutor(new ExecutorThreadFactory()); | |
43 private Thread mExecutorThread; | |
44 | |
45 private class ExecutorThreadFactory implements ThreadFactory { | |
46 public Thread newThread(Runnable r) { | |
47 mExecutorThread = new Thread(r); | |
48 return mExecutorThread; | |
49 } | |
50 } | 54 } |
51 | 55 |
52 @Override | 56 static String getEchoAllHeadersUrl() { |
53 public void onRequestHeadersSent(BidirectionalStream stream) {} | 57 return getBaseUrl() + "echoallheaders"; |
| 58 } |
54 | 59 |
55 @Override | 60 static String getEchoHeaderUrl(String headerName) { |
56 public void onResponseHeadersReceived(BidirectionalStream stream, UrlRes
ponseInfo info) {} | 61 return getBaseUrl() + "echoheader?" + headerName; |
| 62 } |
57 | 63 |
58 @Override | 64 static String getEchoMethodUrl() { |
59 public void onReadCompleted( | 65 return getBaseUrl() + "echomethod"; |
60 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf
fer) {} | 66 } |
61 | 67 |
62 @Override | 68 static String getEchoStreamUrl() { |
63 public void onWriteCompleted( | 69 return getBaseUrl() + "echostream"; |
64 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf
fer) {} | 70 } |
65 | 71 |
66 @Override | 72 static String getEchoTrailersUrl() { |
67 public void onResponseTrailersReceived(BidirectionalStream stream, UrlRe
sponseInfo info, | 73 return getBaseUrl() + "echotrailers"; |
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 } | 74 } |
83 } | 75 } |
84 | 76 |
| 77 private TestBidirectionalStreamCallback startAndWaitForComplete(String url)
throws Exception { |
| 78 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 79 |
| 80 // Create stream. |
| 81 BidirectionalStream stream = |
| 82 new BidirectionalStream.Builder(url, callback, callback.getExecu
tor(), |
| 83 mTestFramework.mCronetEngine) |
| 84 .setHttpMethod("GET") |
| 85 .build(); |
| 86 stream.start(); |
| 87 callback.blockForDone(); |
| 88 assertTrue(stream.isDone()); |
| 89 return callback; |
| 90 } |
| 91 |
| 92 private void checkResponseInfo(UrlResponseInfo responseInfo, String expected
Url, |
| 93 int expectedHttpStatusCode, String expectedHttpStatusText) { |
| 94 assertEquals(expectedUrl, responseInfo.getUrl()); |
| 95 assertEquals( |
| 96 expectedUrl, responseInfo.getUrlChain().get(responseInfo.getUrlC
hain().size() - 1)); |
| 97 assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode()); |
| 98 assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText()); |
| 99 assertFalse(responseInfo.wasCached()); |
| 100 assertTrue(responseInfo.toString().length() > 0); |
| 101 } |
| 102 |
| 103 private static String makeLongString(String base, int repetition) { |
| 104 StringBuilder builder = new StringBuilder(base.length() * repetition); |
| 105 for (int i = 0; i < repetition; ++i) { |
| 106 builder.append(i); |
| 107 builder.append(base); |
| 108 } |
| 109 return builder.toString(); |
| 110 } |
| 111 |
85 @SmallTest | 112 @SmallTest |
86 @Feature({"Cronet"}) | 113 @Feature({"Cronet"}) |
87 public void testBuilderChecks() throws Exception { | 114 public void testBuilderChecks() throws Exception { |
88 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); | 115 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
89 try { | 116 try { |
90 new BidirectionalStream.Builder( | 117 new BidirectionalStream.Builder( |
91 null, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); | 118 null, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); |
92 fail("URL not null-checked"); | 119 fail("URL not null-checked"); |
93 } catch (NullPointerException e) { | 120 } catch (NullPointerException e) { |
94 assertEquals("URL is required.", e.getMessage()); | 121 assertEquals("URL is required.", e.getMessage()); |
(...skipping 16 matching lines...) Expand all Loading... |
111 new BidirectionalStream.Builder( | 138 new BidirectionalStream.Builder( |
112 NativeTestServer.getRedirectURL(), callback, callback.getExe
cutor(), null); | 139 NativeTestServer.getRedirectURL(), callback, callback.getExe
cutor(), null); |
113 fail("CronetEngine not null-checked"); | 140 fail("CronetEngine not null-checked"); |
114 } catch (NullPointerException e) { | 141 } catch (NullPointerException e) { |
115 assertEquals("CronetEngine is required.", e.getMessage()); | 142 assertEquals("CronetEngine is required.", e.getMessage()); |
116 } | 143 } |
117 // Verify successful creation doesn't throw. | 144 // Verify successful creation doesn't throw. |
118 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb
ack, | 145 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb
ack, |
119 callback.getExecutor(), mTestFramework.mCronetEngine); | 146 callback.getExecutor(), mTestFramework.mCronetEngine); |
120 } | 147 } |
| 148 |
| 149 @SmallTest |
| 150 @Feature({"Cronet"}) |
| 151 public void testFailPlainHttp() throws Exception { |
| 152 String url = NativeTestServer.getEchoMethodURL(); |
| 153 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url); |
| 154 assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_
SCHEME", |
| 155 callback.mError.getMessage()); |
| 156 } |
| 157 |
| 158 @SmallTest |
| 159 @Feature({"Cronet"}) |
| 160 public void testSimpleGet() throws Exception { |
| 161 String url = TestHttp2Server.getEchoMethodUrl(); |
| 162 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url); |
| 163 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 164 // Default method is 'GET'. |
| 165 assertEquals("GET", callback.mResponseAsString); |
| 166 assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s], httpSt
atus = 200 , " |
| 167 + "headers = [:status=200], wasCached = fal
se, " |
| 168 + "negotiatedProtocol = h2, proxyServer= nu
ll, " |
| 169 + "receivedBytesCount = 0", |
| 170 url, url), |
| 171 callback.mResponseInfo.toString()); |
| 172 checkResponseInfo(callback.mResponseInfo, TestHttp2Server.getEchoMethodU
rl(), 200, ""); |
| 173 } |
| 174 |
| 175 @SmallTest |
| 176 @Feature({"Cronet"}) |
| 177 public void testSimplePost() throws Exception { |
| 178 String url = TestHttp2Server.getBaseUrl(); |
| 179 mTestFramework.startNetLog(); |
| 180 |
| 181 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 182 callback.addWriteData("Test String".getBytes()); |
| 183 callback.addWriteData("1234567890".getBytes()); |
| 184 callback.addWriteData("woot!".getBytes()); |
| 185 |
| 186 // Create stream. |
| 187 BidirectionalStream stream = |
| 188 new BidirectionalStream.Builder(url, callback, callback.getExecu
tor(), |
| 189 mTestFramework.mCronetEngine) |
| 190 .addHeader("foo", "bar") |
| 191 .addHeader("Content-Type", "zebra") |
| 192 .build(); |
| 193 stream.start(); |
| 194 callback.blockForDone(); |
| 195 assertTrue(stream.isDone()); |
| 196 |
| 197 mTestFramework.stopNetLog(); |
| 198 |
| 199 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 200 assertEquals("woot!", callback.mResponseAsString); |
| 201 } |
| 202 |
| 203 @SmallTest |
| 204 @Feature({"Cronet"}) |
| 205 public void testSetHttpMethod() throws Exception { |
| 206 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 207 callback.addWriteData("Put This Data!".getBytes()); |
| 208 |
| 209 String methodName = "PUT"; |
| 210 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( |
| 211 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); |
| 212 // Try to set 'null' method. |
| 213 try { |
| 214 builder.setHttpMethod(null); |
| 215 fail("Exception not thrown"); |
| 216 } catch (NullPointerException e) { |
| 217 assertEquals("Method is required.", e.getMessage()); |
| 218 } |
| 219 |
| 220 builder.setHttpMethod(methodName); |
| 221 builder.build().start(); |
| 222 callback.blockForDone(); |
| 223 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 224 assertEquals("Put This Data!", callback.mResponseAsString); |
| 225 } |
| 226 |
| 227 @SmallTest |
| 228 @Feature({"Cronet"}) |
| 229 public void testBadMethod() throws Exception { |
| 230 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 231 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( |
| 232 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); |
| 233 try { |
| 234 builder.setHttpMethod("bad:method!"); |
| 235 builder.build().start(); |
| 236 fail("IllegalArgumentException not thrown."); |
| 237 } catch (IllegalArgumentException e) { |
| 238 assertEquals("Invalid http method bad:method!", e.getMessage()); |
| 239 } |
| 240 } |
| 241 |
| 242 @SmallTest |
| 243 @Feature({"Cronet"}) |
| 244 public void testBadHeaderName() throws Exception { |
| 245 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 246 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( |
| 247 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); |
| 248 try { |
| 249 builder.addHeader("header:name", "headervalue"); |
| 250 builder.build().start(); |
| 251 fail("IllegalArgumentException not thrown."); |
| 252 } catch (IllegalArgumentException e) { |
| 253 assertEquals("Invalid header header:name=headervalue", e.getMessage(
)); |
| 254 } |
| 255 } |
| 256 |
| 257 @SmallTest |
| 258 @Feature({"Cronet"}) |
| 259 public void testBadHeaderValue() throws Exception { |
| 260 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 261 BidirectionalStream.Builder builder = new BidirectionalStream.Builder( |
| 262 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron
etEngine); |
| 263 try { |
| 264 builder.addHeader("headername", "bad header\r\nvalue"); |
| 265 builder.build().start(); |
| 266 fail("IllegalArgumentException not thrown."); |
| 267 } catch (IllegalArgumentException e) { |
| 268 assertEquals("Invalid header headername=bad header\r\nvalue", e.getM
essage()); |
| 269 } |
| 270 } |
| 271 |
| 272 @SmallTest |
| 273 @Feature({"Cronet"}) |
| 274 public void testAddHeader() throws Exception { |
| 275 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 276 String headerName = "header-name"; |
| 277 String headerValue = "header-value"; |
| 278 BidirectionalStream.Builder builder = |
| 279 new BidirectionalStream.Builder(TestHttp2Server.getEchoHeaderUrl
(headerName), |
| 280 callback, callback.getExecutor(), mTestFramework.mCronet
Engine); |
| 281 |
| 282 builder.addHeader(headerName, headerValue); |
| 283 builder.setHttpMethod("GET"); |
| 284 builder.build().start(); |
| 285 callback.blockForDone(); |
| 286 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 287 assertEquals(headerValue, callback.mResponseAsString); |
| 288 } |
| 289 |
| 290 @SmallTest |
| 291 @Feature({"Cronet"}) |
| 292 public void testMultiRequestHeaders() throws Exception { |
| 293 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 294 String headerName = "header-name"; |
| 295 String headerValue1 = "header-value1"; |
| 296 String headerValue2 = "header-value2"; |
| 297 BidirectionalStream.Builder builder = |
| 298 new BidirectionalStream.Builder(TestHttp2Server.getEchoAllHeader
sUrl(), callback, |
| 299 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 300 builder.addHeader(headerName, headerValue1); |
| 301 builder.addHeader(headerName, headerValue2); |
| 302 builder.setHttpMethod("GET"); |
| 303 builder.build().start(); |
| 304 callback.blockForDone(); |
| 305 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 306 String headers = callback.mResponseAsString; |
| 307 Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n"); |
| 308 Matcher matcher = pattern.matcher(headers); |
| 309 List<String> actualValues = new ArrayList<String>(); |
| 310 while (matcher.find()) { |
| 311 actualValues.add(matcher.group(1)); |
| 312 } |
| 313 assertEquals(1, actualValues.size()); |
| 314 assertEquals("header-value2", actualValues.get(0)); |
| 315 } |
| 316 |
| 317 @SmallTest |
| 318 @Feature({"Cronet"}) |
| 319 public void testEchoTrailers() throws Exception { |
| 320 mTestFramework.startNetLog(); |
| 321 |
| 322 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 323 String headerName = "header-name"; |
| 324 String headerValue = "header-value"; |
| 325 BidirectionalStream.Builder builder = |
| 326 new BidirectionalStream.Builder(TestHttp2Server.getEchoTrailersU
rl(), callback, |
| 327 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 328 builder.addHeader(headerName, headerValue); |
| 329 builder.setHttpMethod("GET"); |
| 330 builder.build().start(); |
| 331 callback.blockForDone(); |
| 332 mTestFramework.stopNetLog(); |
| 333 |
| 334 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 335 assertNotNull(callback.mTrailers); |
| 336 assertEquals(headerValue, callback.mTrailers.getAsMap().get(headerName).
get(0)); |
| 337 } |
| 338 |
| 339 @SmallTest |
| 340 @Feature({"Cronet"}) |
| 341 public void testCustomUserAgent() throws Exception { |
| 342 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 343 String userAgentName = "User-Agent"; |
| 344 String userAgentValue = "User-Agent-Value"; |
| 345 BidirectionalStream.Builder builder = |
| 346 new BidirectionalStream.Builder(TestHttp2Server.getEchoHeaderUrl
(userAgentName), |
| 347 callback, callback.getExecutor(), mTestFramework.mCronet
Engine); |
| 348 builder.setHttpMethod("GET"); |
| 349 builder.addHeader(userAgentName, userAgentValue); |
| 350 builder.build().start(); |
| 351 callback.blockForDone(); |
| 352 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 353 assertEquals(userAgentValue, callback.mResponseAsString); |
| 354 } |
| 355 |
| 356 @SmallTest |
| 357 @Feature({"Cronet"}) |
| 358 public void testEchoStream() throws Exception { |
| 359 String url = TestHttp2Server.getEchoStreamUrl(); |
| 360 mTestFramework.startNetLog(); |
| 361 |
| 362 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 363 String[] testData = {"Test String", makeLongString("1234567890", 50000),
"woot!"}; |
| 364 StringBuilder stringData = new StringBuilder(); |
| 365 for (String writeData : testData) { |
| 366 callback.addWriteData(writeData.getBytes()); |
| 367 stringData.append(writeData); |
| 368 } |
| 369 |
| 370 // Create stream. |
| 371 BidirectionalStream stream = |
| 372 new BidirectionalStream.Builder(url, callback, callback.getExecu
tor(), |
| 373 mTestFramework.mCronetEngine) |
| 374 .addHeader("foo", "Value with Spaces") |
| 375 .addHeader("Content-Type", "zebra") |
| 376 .build(); |
| 377 stream.start(); |
| 378 callback.blockForDone(); |
| 379 assertTrue(stream.isDone()); |
| 380 |
| 381 mTestFramework.stopNetLog(); |
| 382 |
| 383 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 384 assertEquals(stringData.toString(), callback.mResponseAsString); |
| 385 assertEquals("Value with Spaces", callback.mResponseInfo.getAllHeaders()
.get("foo").get(0)); |
| 386 assertEquals("zebra", callback.mResponseInfo.getAllHeaders().get("Conten
t-Type").get(0)); |
| 387 } |
| 388 |
| 389 /** |
| 390 * Checks that the buffer is updated correctly, when starting at an offset. |
| 391 */ |
| 392 @SmallTest |
| 393 @Feature({"Cronet"}) |
| 394 public void testSimpleGetBufferUpdates() throws Exception { |
| 395 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 396 callback.setAutoAdvance(false); |
| 397 // Since themethod is "GET", the expected response body is also "GET". |
| 398 BidirectionalStream.Builder builder = |
| 399 new BidirectionalStream.Builder(TestHttp2Server.getEchoMethodUrl
(), callback, |
| 400 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 401 BidirectionalStream stream = builder.setHttpMethod("GET").build(); |
| 402 stream.start(); |
| 403 callback.waitForNextReadStep(); |
| 404 |
| 405 assertEquals(null, callback.mError); |
| 406 assertFalse(callback.isDone()); |
| 407 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST
ARTED, |
| 408 callback.mResponseStep); |
| 409 |
| 410 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); |
| 411 readBuffer.put("FOR".getBytes()); |
| 412 assertEquals(3, readBuffer.position()); |
| 413 |
| 414 // Read first two characters of the response ("GE"). It's theoretically |
| 415 // possible to need one read per character, though in practice, |
| 416 // shouldn't happen. |
| 417 while (callback.mResponseAsString.length() < 2) { |
| 418 assertFalse(callback.isDone()); |
| 419 callback.startNextRead(stream, readBuffer); |
| 420 callback.waitForNextReadStep(); |
| 421 } |
| 422 |
| 423 // Make sure the two characters were read. |
| 424 assertEquals("GE", callback.mResponseAsString); |
| 425 |
| 426 // Check the contents of the entire buffer. The first 3 characters |
| 427 // should not have been changed, and the last two should be the first |
| 428 // two characters from the response. |
| 429 assertEquals("FORGE", bufferContentsToString(readBuffer, 0, 5)); |
| 430 // The limit and position should be 5. |
| 431 assertEquals(5, readBuffer.limit()); |
| 432 assertEquals(5, readBuffer.position()); |
| 433 |
| 434 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); |
| 435 |
| 436 // Start reading from position 3. Since the only remaining character |
| 437 // from the response is a "T", when the read completes, the buffer |
| 438 // should contain "FORTE", with a position() of 4 and a limit() of 5. |
| 439 readBuffer.position(3); |
| 440 callback.startNextRead(stream, readBuffer); |
| 441 callback.waitForNextReadStep(); |
| 442 |
| 443 // Make sure all three characters of the response have now been read. |
| 444 assertEquals("GET", callback.mResponseAsString); |
| 445 |
| 446 // Check the entire contents of the buffer. Only the third character |
| 447 // should have been modified. |
| 448 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); |
| 449 |
| 450 // Make sure position and limit were updated correctly. |
| 451 assertEquals(4, readBuffer.position()); |
| 452 assertEquals(5, readBuffer.limit()); |
| 453 |
| 454 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); |
| 455 |
| 456 // One more read attempt. The request should complete. |
| 457 readBuffer.position(1); |
| 458 readBuffer.limit(5); |
| 459 callback.startNextRead(stream, readBuffer); |
| 460 callback.waitForNextReadStep(); |
| 461 |
| 462 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 463 assertEquals("GET", callback.mResponseAsString); |
| 464 checkResponseInfo(callback.mResponseInfo, TestHttp2Server.getEchoMethodU
rl(), 200, ""); |
| 465 |
| 466 // Check that buffer contents were not modified. |
| 467 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); |
| 468 |
| 469 // Position should not have been modified, since nothing was read. |
| 470 assertEquals(1, readBuffer.position()); |
| 471 // Limit should be unchanged as always. |
| 472 assertEquals(5, readBuffer.limit()); |
| 473 |
| 474 assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep); |
| 475 |
| 476 // Make sure there are no other pending messages, which would trigger |
| 477 // asserts in TestBidirectionalCallback. |
| 478 testSimpleGet(); |
| 479 } |
| 480 |
| 481 @SmallTest |
| 482 @Feature({"Cronet"}) |
| 483 public void testBadBuffers() throws Exception { |
| 484 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 485 callback.setAutoAdvance(false); |
| 486 BidirectionalStream.Builder builder = |
| 487 new BidirectionalStream.Builder(TestHttp2Server.getEchoMethodUrl
(), callback, |
| 488 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 489 BidirectionalStream stream = builder.setHttpMethod("GET").build(); |
| 490 stream.start(); |
| 491 callback.waitForNextReadStep(); |
| 492 |
| 493 assertEquals(null, callback.mError); |
| 494 assertFalse(callback.isDone()); |
| 495 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST
ARTED, |
| 496 callback.mResponseStep); |
| 497 |
| 498 // Try to read using a full buffer. |
| 499 try { |
| 500 ByteBuffer readBuffer = ByteBuffer.allocateDirect(4); |
| 501 readBuffer.put("full".getBytes()); |
| 502 stream.read(readBuffer); |
| 503 fail("Exception not thrown"); |
| 504 } catch (IllegalArgumentException e) { |
| 505 assertEquals("ByteBuffer is already full.", e.getMessage()); |
| 506 } |
| 507 |
| 508 // Try to read using a non-direct buffer. |
| 509 try { |
| 510 ByteBuffer readBuffer = ByteBuffer.allocate(5); |
| 511 stream.read(readBuffer); |
| 512 fail("Exception not thrown"); |
| 513 } catch (Exception e) { |
| 514 assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage
()); |
| 515 } |
| 516 |
| 517 // Finish the stream with a direct ByteBuffer. |
| 518 callback.setAutoAdvance(true); |
| 519 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); |
| 520 stream.read(readBuffer); |
| 521 callback.blockForDone(); |
| 522 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); |
| 523 assertEquals("GET", callback.mResponseAsString); |
| 524 } |
| 525 |
| 526 private void throwOrCancel(FailureType failureType, ResponseStep failureStep
, |
| 527 boolean expectResponseInfo, boolean expectError) { |
| 528 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 529 callback.setFailure(failureType, failureStep); |
| 530 BidirectionalStream.Builder builder = |
| 531 new BidirectionalStream.Builder(TestHttp2Server.getEchoMethodUrl
(), callback, |
| 532 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 533 BidirectionalStream stream = builder.setHttpMethod("GET").build(); |
| 534 stream.start(); |
| 535 callback.blockForDone(); |
| 536 assertEquals(callback.mResponseStep, failureStep); |
| 537 assertTrue(stream.isDone()); |
| 538 assertEquals(expectResponseInfo, callback.mResponseInfo != null); |
| 539 assertEquals(expectError, callback.mError != null); |
| 540 assertEquals(expectError, callback.mOnErrorCalled); |
| 541 assertEquals(failureType == FailureType.CANCEL_SYNC |
| 542 || failureType == FailureType.CANCEL_ASYNC |
| 543 || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE
, |
| 544 callback.mOnCanceledCalled); |
| 545 } |
| 546 |
| 547 @SmallTest |
| 548 @Feature({"Cronet"}) |
| 549 public void testFailures() throws Exception { |
| 550 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_S
ENT, false, false); |
| 551 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_
SENT, false, false); |
| 552 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE
QUEST_HEADERS_SENT, |
| 553 false, false); |
| 554 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SE
NT, false, true); |
| 555 |
| 556 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED,
true, false); |
| 557 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED
, true, false); |
| 558 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE
SPONSE_STARTED, |
| 559 true, false); |
| 560 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED,
true, true); |
| 561 |
| 562 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, t
rue, false); |
| 563 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED,
true, false); |
| 564 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE
AD_COMPLETED, true, |
| 565 false); |
| 566 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, tr
ue, true); |
| 567 } |
| 568 |
| 569 @SmallTest |
| 570 @Feature({"Cronet"}) |
| 571 public void testThrowOnSucceeded() { |
| 572 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 573 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED); |
| 574 BidirectionalStream.Builder builder = |
| 575 new BidirectionalStream.Builder(TestHttp2Server.getEchoMethodUrl
(), callback, |
| 576 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 577 BidirectionalStream stream = builder.setHttpMethod("GET").build(); |
| 578 stream.start(); |
| 579 callback.blockForDone(); |
| 580 assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED); |
| 581 assertTrue(stream.isDone()); |
| 582 assertNotNull(callback.mResponseInfo); |
| 583 assertNull(callback.mError); |
| 584 assertFalse(callback.mOnErrorCalled); |
| 585 } |
| 586 |
| 587 @SmallTest |
| 588 @Feature({"Cronet"}) |
| 589 public void testExecutorShutdown() { |
| 590 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa
llback(); |
| 591 |
| 592 callback.setAutoAdvance(false); |
| 593 BidirectionalStream.Builder builder = |
| 594 new BidirectionalStream.Builder(TestHttp2Server.getEchoMethodUrl
(), callback, |
| 595 callback.getExecutor(), mTestFramework.mCronetEngine); |
| 596 CronetBidirectionalStream stream = |
| 597 (CronetBidirectionalStream) builder.setHttpMethod("GET").build()
; |
| 598 stream.start(); |
| 599 callback.waitForNextReadStep(); |
| 600 assertFalse(callback.isDone()); |
| 601 assertFalse(stream.isDone()); |
| 602 |
| 603 final ConditionVariable requestDestroyed = new ConditionVariable(false); |
| 604 stream.setOnDestroyedCallbackForTests(new Runnable() { |
| 605 @Override |
| 606 public void run() { |
| 607 requestDestroyed.open(); |
| 608 } |
| 609 }); |
| 610 |
| 611 // Shutdown the executor, so posting the task will throw an exception. |
| 612 callback.shutdownExecutor(); |
| 613 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); |
| 614 stream.read(readBuffer); |
| 615 // Callback will never be called again because executor is shutdown, |
| 616 // but stream will be destroyed from network thread. |
| 617 requestDestroyed.block(); |
| 618 |
| 619 assertFalse(callback.isDone()); |
| 620 assertTrue(stream.isDone()); |
| 621 } |
| 622 |
| 623 // Returns the contents of byteBuffer, from its position() to its limit(), |
| 624 // as a String. Does not modify byteBuffer's position(). |
| 625 private String bufferContentsToString(ByteBuffer byteBuffer, int start, int
end) { |
| 626 // Use a duplicate to avoid modifying byteBuffer. |
| 627 ByteBuffer duplicate = byteBuffer.duplicate(); |
| 628 duplicate.position(start); |
| 629 duplicate.limit(end); |
| 630 byte[] contents = new byte[duplicate.remaining()]; |
| 631 duplicate.get(contents); |
| 632 return new String(contents); |
| 633 } |
121 } | 634 } |
OLD | NEW |