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