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 |