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.CronetTestBase.OnlyRunNativeCronet; | |
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.AbstractMap; |
13 import java.util.concurrent.ExecutorService; | 17 import java.util.ArrayList; |
14 import java.util.concurrent.Executors; | 18 import java.util.Arrays; |
15 import java.util.concurrent.ThreadFactory; | 19 import java.util.List; |
20 import java.util.Map; | |
21 import java.util.regex.Matcher; | |
22 import java.util.regex.Pattern; | |
16 | 23 |
17 /** | 24 /** |
18 * Test functionality of BidirectionalStream interface. | 25 * Test functionality of BidirectionalStream interface. |
19 */ | 26 */ |
20 public class BidirectionalStreamTest extends CronetTestBase { | 27 public class BidirectionalStreamTest extends CronetTestBase { |
21 private CronetTestFramework mTestFramework; | 28 private CronetTestFramework mTestFramework; |
22 | 29 |
23 @Override | 30 @Override |
24 protected void setUp() throws Exception { | 31 protected void setUp() throws Exception { |
25 super.setUp(); | 32 super.setUp(); |
26 mTestFramework = startCronetTestFramework(); | 33 // Load library first to create MockCertVerifier. |
27 assertTrue(NativeTestServer.startNativeTestServer(getContext())); | 34 System.loadLibrary("cronet_tests"); |
28 // Add url interceptors after native application context is initialized. | 35 CronetEngine.Builder builder = new CronetEngine.Builder(getContext()); |
29 MockUrlRequestJobFactory.setUp(); | 36 builder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerif ier()); |
37 | |
38 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n ull, builder); | |
39 assertTrue(Http2TestServer.startHttp2TestServer( | |
40 getContext(), QuicTestServer.getServerCert(), QuicTestServer.get ServerCertKey())); | |
30 } | 41 } |
31 | 42 |
32 @Override | 43 @Override |
33 protected void tearDown() throws Exception { | 44 protected void tearDown() throws Exception { |
34 NativeTestServer.shutdownNativeTestServer(); | 45 assertTrue(Http2TestServer.shutdownHttp2TestServer()); |
35 mTestFramework.mCronetEngine.shutdown(); | 46 if (mTestFramework.mCronetEngine != null) { |
47 mTestFramework.mCronetEngine.shutdown(); | |
48 } | |
36 super.tearDown(); | 49 super.tearDown(); |
37 } | 50 } |
38 | 51 |
39 private class TestBidirectionalStreamCallback extends BidirectionalStream.Ca llback { | 52 private static void checkResponseInfo(UrlResponseInfo responseInfo, String e xpectedUrl, |
40 // Executor Service for Cronet callbacks. | 53 int expectedHttpStatusCode, String expectedHttpStatusText) { |
41 private final ExecutorService mExecutorService = | 54 assertEquals(expectedUrl, responseInfo.getUrl()); |
42 Executors.newSingleThreadExecutor(new ExecutorThreadFactory()); | 55 assertEquals( |
43 private Thread mExecutorThread; | 56 expectedUrl, responseInfo.getUrlChain().get(responseInfo.getUrlC hain().size() - 1)); |
57 assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode()); | |
58 assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText()); | |
59 assertFalse(responseInfo.wasCached()); | |
60 assertTrue(responseInfo.toString().length() > 0); | |
61 } | |
44 | 62 |
45 private class ExecutorThreadFactory implements ThreadFactory { | 63 private static String createLongString(String base, int repetition) { |
46 public Thread newThread(Runnable r) { | 64 StringBuilder builder = new StringBuilder(base.length() * repetition); |
47 mExecutorThread = new Thread(r); | 65 for (int i = 0; i < repetition; ++i) { |
48 return mExecutorThread; | 66 builder.append(i); |
49 } | 67 builder.append(base); |
50 } | 68 } |
69 return builder.toString(); | |
70 } | |
51 | 71 |
52 @Override | 72 private static UrlResponseInfo createUrlResponseInfo( |
53 public void onRequestHeadersSent(BidirectionalStream stream) {} | 73 String[] urls, String message, int statusCode, int receivedBytes, St ring... headers) { |
54 | 74 ArrayList<Map.Entry<String, String>> headersList = new ArrayList<>(); |
55 @Override | 75 for (int i = 0; i < headers.length; i += 2) { |
56 public void onResponseHeadersReceived(BidirectionalStream stream, UrlRes ponseInfo info) {} | 76 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String> ( |
57 | 77 headers[i], headers[i + 1])); |
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 } | 78 } |
79 UrlResponseInfo urlResponseInfo = new UrlResponseInfo( | |
80 Arrays.asList(urls), statusCode, message, headersList, false, "h 2", null); | |
81 urlResponseInfo.setReceivedBytesCount(receivedBytes); | |
82 return urlResponseInfo; | |
83 } | 83 } |
84 | 84 |
85 @SmallTest | 85 @SmallTest |
86 @Feature({"Cronet"}) | 86 @Feature({"Cronet"}) |
87 public void testBuilderChecks() throws Exception { | 87 public void testBuilderChecks() throws Exception { |
88 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | 88 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); |
89 try { | 89 try { |
90 new BidirectionalStream.Builder( | 90 new BidirectionalStream.Builder( |
91 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine); | 91 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine); |
92 fail("URL not null-checked"); | 92 fail("URL not null-checked"); |
93 } catch (NullPointerException e) { | 93 } catch (NullPointerException e) { |
94 assertEquals("URL is required.", e.getMessage()); | 94 assertEquals("URL is required.", e.getMessage()); |
95 } | 95 } |
96 try { | 96 try { |
97 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), n ull, | 97 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), null , |
98 callback.getExecutor(), mTestFramework.mCronetEngine); | 98 callback.getExecutor(), mTestFramework.mCronetEngine); |
99 fail("Callback not null-checked"); | 99 fail("Callback not null-checked"); |
100 } catch (NullPointerException e) { | 100 } catch (NullPointerException e) { |
101 assertEquals("Callback is required.", e.getMessage()); | 101 assertEquals("Callback is required.", e.getMessage()); |
102 } | 102 } |
103 try { | 103 try { |
104 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), c allback, null, | 104 new BidirectionalStream.Builder( |
105 mTestFramework.mCronetEngine); | 105 Http2TestServer.getServerUrl(), callback, null, mTestFramewo rk.mCronetEngine); |
106 fail("Executor not null-checked"); | 106 fail("Executor not null-checked"); |
107 } catch (NullPointerException e) { | 107 } catch (NullPointerException e) { |
108 assertEquals("Executor is required.", e.getMessage()); | 108 assertEquals("Executor is required.", e.getMessage()); |
109 } | 109 } |
110 try { | 110 try { |
111 new BidirectionalStream.Builder( | 111 new BidirectionalStream.Builder( |
112 NativeTestServer.getRedirectURL(), callback, callback.getExe cutor(), null); | 112 Http2TestServer.getServerUrl(), callback, callback.getExecut or(), null); |
113 fail("CronetEngine not null-checked"); | 113 fail("CronetEngine not null-checked"); |
114 } catch (NullPointerException e) { | 114 } catch (NullPointerException e) { |
115 assertEquals("CronetEngine is required.", e.getMessage()); | 115 assertEquals("CronetEngine is required.", e.getMessage()); |
116 } | 116 } |
117 // Verify successful creation doesn't throw. | 117 // Verify successful creation doesn't throw. |
118 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb ack, | 118 BidirectionalStream.Builder builder = |
119 callback.getExecutor(), mTestFramework.mCronetEngine); | 119 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback, |
120 callback.getExecutor(), mTestFramework.mCronetEngine); | |
121 try { | |
122 builder.addHeader(null, "value"); | |
123 fail("Header name is not null-checked"); | |
124 } catch (NullPointerException e) { | |
125 assertEquals("Invalid header name.", e.getMessage()); | |
126 } | |
127 try { | |
128 builder.addHeader("name", null); | |
129 fail("Header value is not null-checked"); | |
130 } catch (NullPointerException e) { | |
131 assertEquals("Invalid header value.", e.getMessage()); | |
132 } | |
133 try { | |
134 builder.setHttpMethod(null); | |
135 fail("Method name is not null-checked"); | |
136 } catch (NullPointerException e) { | |
137 assertEquals("Method is required.", e.getMessage()); | |
138 } | |
139 } | |
140 | |
141 @SmallTest | |
142 @Feature({"Cronet"}) | |
143 @OnlyRunNativeCronet | |
144 public void testFailPlainHttp() throws Exception { | |
145 String url = "http://example.com"; | |
146 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
147 // Create stream. | |
148 BidirectionalStream stream = new BidirectionalStream | |
149 .Builder(url, callback, callback.ge tExecutor(), | |
150 mTestFramework.mCronetEngin e) | |
151 .build(); | |
152 stream.start(); | |
153 callback.blockForDone(); | |
154 assertTrue(stream.isDone()); | |
155 assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_ SCHEME", | |
156 callback.mError.getMessage()); | |
157 } | |
158 | |
159 @SmallTest | |
160 @Feature({"Cronet"}) | |
161 @OnlyRunNativeCronet | |
162 public void testSimpleGet() throws Exception { | |
163 String url = Http2TestServer.getEchoMethodUrl(); | |
164 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
165 // Create stream. | |
166 BidirectionalStream stream = new BidirectionalStream | |
167 .Builder(url, callback, callback.ge tExecutor(), | |
168 mTestFramework.mCronetEngin e) | |
169 .setHttpMethod("GET") | |
170 .build(); | |
171 stream.start(); | |
172 callback.blockForDone(); | |
173 assertTrue(stream.isDone()); | |
174 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
175 // Default method is 'GET'. | |
176 assertEquals("GET", callback.mResponseAsString); | |
177 UrlResponseInfo urlResponseInfo = | |
178 createUrlResponseInfo(new String[] {url}, "", 200, 27, ":status" , "200"); | |
179 assertResponseEquals(urlResponseInfo, callback.mResponseInfo); | |
180 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
181 } | |
182 | |
183 @SmallTest | |
184 @Feature({"Cronet"}) | |
185 @OnlyRunNativeCronet | |
186 public void testSimpleHead() throws Exception { | |
187 String url = Http2TestServer.getEchoMethodUrl(); | |
188 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
189 // Create stream. | |
190 BidirectionalStream stream = new BidirectionalStream | |
191 .Builder(url, callback, callback.ge tExecutor(), | |
192 mTestFramework.mCronetEngin e) | |
193 .setHttpMethod("HEAD") | |
194 .build(); | |
195 stream.start(); | |
196 callback.blockForDone(); | |
197 assertTrue(stream.isDone()); | |
198 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
199 assertEquals("HEAD", callback.mResponseAsString); | |
200 UrlResponseInfo urlResponseInfo = | |
201 createUrlResponseInfo(new String[] {url}, "", 200, 28, ":status" , "200"); | |
202 assertResponseEquals(urlResponseInfo, callback.mResponseInfo); | |
203 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
204 } | |
205 | |
206 @SmallTest | |
207 @Feature({"Cronet"}) | |
208 @OnlyRunNativeCronet | |
209 public void testSimplePost() throws Exception { | |
210 String url = Http2TestServer.getEchoStreamUrl(); | |
211 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
212 callback.addWriteData("Test String".getBytes()); | |
213 callback.addWriteData("1234567890".getBytes()); | |
214 callback.addWriteData("woot!".getBytes()); | |
215 // Create stream. | |
216 BidirectionalStream stream = new BidirectionalStream | |
217 .Builder(url, callback, callback.ge tExecutor(), | |
218 mTestFramework.mCronetEngin e) | |
219 .addHeader("foo", "bar") | |
220 .addHeader("empty", "") | |
221 .addHeader("Content-Type", "zebra") | |
222 .build(); | |
223 stream.start(); | |
224 callback.blockForDone(); | |
225 assertTrue(stream.isDone()); | |
226 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
227 assertEquals("Test String1234567890woot!", callback.mResponseAsString); | |
228 assertEquals("bar", callback.mResponseInfo.getAllHeaders().get("echo-foo ").get(0)); | |
229 assertEquals("", callback.mResponseInfo.getAllHeaders().get("echo-empty" ).get(0)); | |
230 assertEquals( | |
231 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0)); | |
232 } | |
233 | |
234 @SmallTest | |
235 @Feature({"Cronet"}) | |
236 @OnlyRunNativeCronet | |
237 public void testSimplePut() throws Exception { | |
238 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
239 callback.addWriteData("Put This Data!".getBytes()); | |
240 String methodName = "PUT"; | |
241 BidirectionalStream.Builder builder = | |
242 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback, | |
243 callback.getExecutor(), mTestFramework.mCronetEngine); | |
244 builder.setHttpMethod(methodName); | |
245 builder.build().start(); | |
246 callback.blockForDone(); | |
247 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
248 assertEquals("Put This Data!", callback.mResponseAsString); | |
249 assertEquals(methodName, callback.mResponseInfo.getAllHeaders().get("ech o-method").get(0)); | |
250 } | |
251 | |
252 @SmallTest | |
253 @Feature({"Cronet"}) | |
254 @OnlyRunNativeCronet | |
255 public void testBadMethod() throws Exception { | |
256 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
257 BidirectionalStream.Builder builder = | |
258 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback, | |
259 callback.getExecutor(), mTestFramework.mCronetEngine); | |
260 try { | |
261 builder.setHttpMethod("bad:method!"); | |
262 builder.build().start(); | |
263 fail("IllegalArgumentException not thrown."); | |
264 } catch (IllegalArgumentException e) { | |
265 assertEquals("Invalid http method bad:method!", e.getMessage()); | |
266 } | |
267 } | |
268 | |
269 @SmallTest | |
270 @Feature({"Cronet"}) | |
271 @OnlyRunNativeCronet | |
272 public void testBadHeaderName() throws Exception { | |
273 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
274 BidirectionalStream.Builder builder = | |
275 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback, | |
276 callback.getExecutor(), mTestFramework.mCronetEngine); | |
277 try { | |
278 builder.addHeader("goodheader1", "headervalue"); | |
279 builder.addHeader("header:name", "headervalue"); | |
280 builder.addHeader("goodheader2", "headervalue"); | |
281 builder.build().start(); | |
282 fail("IllegalArgumentException not thrown."); | |
283 } catch (IllegalArgumentException e) { | |
284 assertEquals("Invalid header header:name=headervalue", e.getMessage( )); | |
285 } | |
286 } | |
287 | |
288 @SmallTest | |
289 @Feature({"Cronet"}) | |
290 @OnlyRunNativeCronet | |
291 public void testBadHeaderValue() throws Exception { | |
292 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
293 BidirectionalStream.Builder builder = | |
294 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback, | |
295 callback.getExecutor(), mTestFramework.mCronetEngine); | |
296 try { | |
297 builder.addHeader("headername", "bad header\r\nvalue"); | |
298 builder.build().start(); | |
299 fail("IllegalArgumentException not thrown."); | |
300 } catch (IllegalArgumentException e) { | |
301 assertEquals("Invalid header headername=bad header\r\nvalue", e.getM essage()); | |
302 } | |
303 } | |
304 | |
305 @SmallTest | |
306 @Feature({"Cronet"}) | |
307 @OnlyRunNativeCronet | |
308 public void testAddHeader() throws Exception { | |
309 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
310 String headerName = "header-name"; | |
311 String headerValue = "header-value"; | |
312 BidirectionalStream.Builder builder = | |
313 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (headerName), | |
314 callback, callback.getExecutor(), mTestFramework.mCronet Engine); | |
315 builder.addHeader(headerName, headerValue); | |
316 builder.setHttpMethod("GET"); | |
317 builder.build().start(); | |
318 callback.blockForDone(); | |
319 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
320 assertEquals(headerValue, callback.mResponseAsString); | |
321 } | |
322 | |
323 @SmallTest | |
324 @Feature({"Cronet"}) | |
325 @OnlyRunNativeCronet | |
326 public void testMultiRequestHeaders() throws Exception { | |
327 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
328 String headerName = "header-name"; | |
329 String headerValue1 = "header-value1"; | |
330 String headerValue2 = "header-value2"; | |
331 BidirectionalStream.Builder builder = | |
332 new BidirectionalStream.Builder(Http2TestServer.getEchoAllHeader sUrl(), callback, | |
333 callback.getExecutor(), mTestFramework.mCronetEngine); | |
334 builder.addHeader(headerName, headerValue1); | |
335 builder.addHeader(headerName, headerValue2); | |
336 builder.setHttpMethod("GET"); | |
337 builder.build().start(); | |
338 callback.blockForDone(); | |
339 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
340 String headers = callback.mResponseAsString; | |
341 Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n"); | |
342 Matcher matcher = pattern.matcher(headers); | |
343 List<String> actualValues = new ArrayList<String>(); | |
344 while (matcher.find()) { | |
345 actualValues.add(matcher.group(1)); | |
346 } | |
347 assertEquals(1, actualValues.size()); | |
348 assertEquals("header-value2", actualValues.get(0)); | |
349 } | |
350 | |
351 @SmallTest | |
352 @Feature({"Cronet"}) | |
353 @OnlyRunNativeCronet | |
354 public void testEchoTrailers() throws Exception { | |
355 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
356 String headerName = "header-name"; | |
357 String headerValue = "header-value"; | |
358 BidirectionalStream.Builder builder = | |
359 new BidirectionalStream.Builder(Http2TestServer.getEchoTrailersU rl(), callback, | |
360 callback.getExecutor(), mTestFramework.mCronetEngine); | |
361 builder.addHeader(headerName, headerValue); | |
362 builder.setHttpMethod("GET"); | |
363 builder.build().start(); | |
364 callback.blockForDone(); | |
365 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
366 assertNotNull(callback.mTrailers); | |
367 // Verify that header value is properly echoed in trailers. | |
368 assertEquals(headerValue, callback.mTrailers.getAsMap().get("echo-" + he aderName).get(0)); | |
369 } | |
370 | |
371 @SmallTest | |
372 @Feature({"Cronet"}) | |
373 @OnlyRunNativeCronet | |
374 public void testCustomUserAgent() throws Exception { | |
375 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
376 String userAgentName = "User-Agent"; | |
377 String userAgentValue = "User-Agent-Value"; | |
378 BidirectionalStream.Builder builder = | |
379 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (userAgentName), | |
380 callback, callback.getExecutor(), mTestFramework.mCronet Engine); | |
381 builder.setHttpMethod("GET"); | |
382 builder.addHeader(userAgentName, userAgentValue); | |
383 builder.build().start(); | |
384 callback.blockForDone(); | |
385 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
386 assertEquals(userAgentValue, callback.mResponseAsString); | |
387 } | |
388 | |
389 @SmallTest | |
390 @Feature({"Cronet"}) | |
391 @OnlyRunNativeCronet | |
392 public void testEchoStream() throws Exception { | |
393 String url = Http2TestServer.getEchoStreamUrl(); | |
394 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
395 String[] testData = {"Test String", createLongString("1234567890", 50000 ), "woot!"}; | |
396 StringBuilder stringData = new StringBuilder(); | |
397 for (String writeData : testData) { | |
398 callback.addWriteData(writeData.getBytes()); | |
399 stringData.append(writeData); | |
400 } | |
401 // Create stream. | |
402 BidirectionalStream stream = new BidirectionalStream | |
403 .Builder(url, callback, callback.ge tExecutor(), | |
404 mTestFramework.mCronetEngin e) | |
405 .addHeader("foo", "Value with Space s") | |
406 .addHeader("Content-Type", "zebra") | |
407 .build(); | |
408 stream.start(); | |
409 callback.blockForDone(); | |
410 assertTrue(stream.isDone()); | |
411 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
412 assertEquals(stringData.toString(), callback.mResponseAsString); | |
413 assertEquals( | |
414 "Value with Spaces", callback.mResponseInfo.getAllHeaders().get( "echo-foo").get(0)); | |
415 assertEquals( | |
416 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0)); | |
417 } | |
418 | |
419 @SmallTest | |
420 @Feature({"Cronet"}) | |
421 @OnlyRunNativeCronet | |
422 public void testEchoStreamEmptyWrite() throws Exception { | |
423 String url = Http2TestServer.getEchoStreamUrl(); | |
424 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
425 callback.addWriteData(new byte[0]); | |
426 // Create stream. | |
427 BidirectionalStream stream = new BidirectionalStream | |
428 .Builder(url, callback, callback.ge tExecutor(), | |
429 mTestFramework.mCronetEngin e) | |
430 .build(); | |
431 stream.start(); | |
432 callback.blockForDone(); | |
433 assertTrue(stream.isDone()); | |
434 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
435 assertEquals("", callback.mResponseAsString); | |
436 } | |
437 | |
438 @SmallTest | |
439 @Feature({"Cronet"}) | |
440 @OnlyRunNativeCronet | |
441 public void testDoubleWrite() throws Exception { | |
442 String url = Http2TestServer.getEchoStreamUrl(); | |
443 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback() { | |
444 @Override | |
445 public void onRequestHeadersSent(BidirectionalStream stream) { | |
446 startNextWrite(stream); | |
447 try { | |
448 // Second write from callback invoked on single-threaded exe cutor throws | |
449 // an exception because first write is still pending until i ts completion | |
450 // is handled on executor. | |
451 ByteBuffer writeBuffer = ByteBuffer.allocateDirect(5); | |
452 writeBuffer.put("abc".getBytes()); | |
453 writeBuffer.flip(); | |
454 stream.write(writeBuffer, false); | |
455 fail("Exception is not thrown."); | |
456 } catch (Exception e) { | |
457 assertEquals("Unexpected write attempt.", e.getMessage()); | |
458 } | |
459 } | |
460 }; | |
461 callback.addWriteData("1".getBytes()); | |
462 callback.addWriteData("2".getBytes()); | |
463 // Create stream. | |
464 BidirectionalStream stream = new BidirectionalStream | |
465 .Builder(url, callback, callback.ge tExecutor(), | |
466 mTestFramework.mCronetEngin e) | |
467 .build(); | |
468 stream.start(); | |
469 callback.blockForDone(); | |
470 assertTrue(stream.isDone()); | |
471 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
472 assertEquals("12", callback.mResponseAsString); | |
473 } | |
474 | |
475 @SmallTest | |
476 @Feature({"Cronet"}) | |
477 @OnlyRunNativeCronet | |
478 public void testDoubleRead() throws Exception { | |
479 String url = Http2TestServer.getEchoStreamUrl(); | |
480 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback() { | |
481 @Override | |
482 public void onResponseHeadersReceived( | |
483 BidirectionalStream stream, UrlResponseInfo info) { | |
484 startNextRead(stream); | |
485 try { | |
486 // Second read from callback invoked on single-threaded exec utor throws | |
487 // an exception because previous read is still pending until its completion | |
488 // is handled on executor. | |
489 stream.read(ByteBuffer.allocateDirect(5)); | |
490 fail("Exception is not thrown."); | |
491 } catch (Exception e) { | |
492 assertEquals("Unexpected read attempt.", e.getMessage()); | |
493 } | |
494 } | |
495 }; | |
496 callback.addWriteData("1".getBytes()); | |
497 callback.addWriteData("2".getBytes()); | |
498 // Create stream. | |
499 BidirectionalStream stream = new BidirectionalStream | |
500 .Builder(url, callback, callback.ge tExecutor(), | |
501 mTestFramework.mCronetEngin e) | |
502 .build(); | |
503 stream.start(); | |
504 callback.blockForDone(); | |
505 assertTrue(stream.isDone()); | |
506 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
507 assertEquals("12", callback.mResponseAsString); | |
508 } | |
509 | |
510 @SmallTest | |
511 @Feature({"Cronet"}) | |
512 @OnlyRunNativeCronet | |
513 public void testReadAndWrite() throws Exception { | |
514 String url = Http2TestServer.getEchoStreamUrl(); | |
515 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback() { | |
516 @Override | |
517 public void onResponseHeadersReceived( | |
518 BidirectionalStream stream, UrlResponseInfo info) { | |
519 // Start the write, that will not complete until callback comple tion. | |
520 startNextWrite(stream); | |
521 // Start the read. It is allowed with write in flight. | |
522 super.onResponseHeadersReceived(stream, info); | |
523 } | |
524 }; | |
525 callback.setAutoAdvance(false); | |
526 callback.addWriteData("1".getBytes()); | |
527 callback.addWriteData("2".getBytes()); | |
528 // Create stream. | |
529 BidirectionalStream stream = new BidirectionalStream | |
530 .Builder(url, callback, callback.ge tExecutor(), | |
531 mTestFramework.mCronetEngin e) | |
532 .build(); | |
533 stream.start(); | |
534 callback.waitForNextWriteStep(); | |
535 callback.waitForNextReadStep(); | |
536 callback.startNextRead(stream); | |
537 callback.setAutoAdvance(true); | |
538 callback.blockForDone(); | |
539 assertTrue(stream.isDone()); | |
540 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
541 assertEquals("12", callback.mResponseAsString); | |
542 } | |
543 | |
544 @SmallTest | |
545 @Feature({"Cronet"}) | |
546 @OnlyRunNativeCronet | |
547 public void testEchoStreamWriteFirst() throws Exception { | |
548 String url = Http2TestServer.getEchoStreamUrl(); | |
549 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
550 callback.setAutoAdvance(false); | |
551 String[] testData = {"a", "bb", "ccc", "Test String", "1234567890", "woo t!"}; | |
552 StringBuilder stringData = new StringBuilder(); | |
553 for (String writeData : testData) { | |
554 callback.addWriteData(writeData.getBytes()); | |
555 stringData.append(writeData); | |
556 } | |
557 // Create stream. | |
558 BidirectionalStream stream = new BidirectionalStream | |
559 .Builder(url, callback, callback.ge tExecutor(), | |
560 mTestFramework.mCronetEngin e) | |
561 .build(); | |
562 stream.start(); | |
563 // Write first. | |
564 callback.waitForNextWriteStep(); | |
565 for (String expected : testData) { | |
566 // Write next chunk of test data. | |
567 callback.startNextWrite(stream); | |
568 callback.waitForNextWriteStep(); | |
569 } | |
570 | |
571 // Read back. | |
572 callback.waitForNextReadStep(); | |
573 assertEquals("", callback.mResponseAsString); | |
xunjieli
2016/01/29 15:08:04
This is a bit surprising. Will this be flaky if th
mef
2016/01/29 15:46:24
That's the point. waitForNextReadStep() just waits
| |
574 callback.setAutoAdvance(true); | |
575 callback.startNextRead(stream); | |
576 callback.blockForDone(); | |
577 assertTrue(stream.isDone()); | |
578 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
579 assertEquals(stringData.toString(), callback.mResponseAsString); | |
580 } | |
581 | |
582 @SmallTest | |
583 @Feature({"Cronet"}) | |
584 @OnlyRunNativeCronet | |
585 public void testEchoStreamStepByStep() throws Exception { | |
586 String url = Http2TestServer.getEchoStreamUrl(); | |
587 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
588 callback.setAutoAdvance(false); | |
589 String[] testData = {"a", "bb", "ccc", "Test String", "1234567890", "woo t!"}; | |
590 StringBuilder stringData = new StringBuilder(); | |
591 for (String writeData : testData) { | |
592 callback.addWriteData(writeData.getBytes()); | |
593 stringData.append(writeData); | |
594 } | |
595 // Create stream. | |
596 BidirectionalStream stream = new BidirectionalStream | |
597 .Builder(url, callback, callback.ge tExecutor(), | |
598 mTestFramework.mCronetEngin e) | |
599 .build(); | |
600 stream.start(); | |
601 callback.waitForNextWriteStep(); | |
602 callback.waitForNextReadStep(); | |
603 | |
604 for (String expected : testData) { | |
605 // Write next chunk of test data. | |
606 callback.startNextWrite(stream); | |
607 callback.waitForNextWriteStep(); | |
608 | |
609 // Read next chunk of test data. | |
610 ByteBuffer readBuffer = ByteBuffer.allocateDirect(100); | |
611 callback.startNextRead(stream, readBuffer); | |
612 callback.waitForNextReadStep(); | |
613 assertEquals(expected.length(), readBuffer.position()); | |
614 assertFalse(stream.isDone()); | |
615 } | |
616 | |
617 callback.setAutoAdvance(true); | |
618 callback.startNextRead(stream); | |
619 callback.blockForDone(); | |
620 assertTrue(stream.isDone()); | |
621 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
622 assertEquals(stringData.toString(), callback.mResponseAsString); | |
623 } | |
624 | |
625 /** | |
626 * Checks that the buffer is updated correctly, when starting at an offset. | |
627 */ | |
628 @SmallTest | |
629 @Feature({"Cronet"}) | |
630 @OnlyRunNativeCronet | |
631 public void testSimpleGetBufferUpdates() throws Exception { | |
632 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
633 callback.setAutoAdvance(false); | |
634 // Since the method is "GET", the expected response body is also "GET". | |
635 BidirectionalStream.Builder builder = | |
636 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
637 callback.getExecutor(), mTestFramework.mCronetEngine); | |
638 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
639 stream.start(); | |
640 callback.waitForNextReadStep(); | |
641 | |
642 assertEquals(null, callback.mError); | |
643 assertFalse(callback.isDone()); | |
644 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED, | |
645 callback.mResponseStep); | |
646 | |
647 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
648 readBuffer.put("FOR".getBytes()); | |
649 assertEquals(3, readBuffer.position()); | |
650 | |
651 // Read first two characters of the response ("GE"). It's theoretically | |
652 // possible to need one read per character, though in practice, | |
653 // shouldn't happen. | |
654 while (callback.mResponseAsString.length() < 2) { | |
655 assertFalse(callback.isDone()); | |
656 callback.startNextRead(stream, readBuffer); | |
657 callback.waitForNextReadStep(); | |
658 } | |
659 | |
660 // Make sure the two characters were read. | |
661 assertEquals("GE", callback.mResponseAsString); | |
662 | |
663 // Check the contents of the entire buffer. The first 3 characters | |
664 // should not have been changed, and the last two should be the first | |
665 // two characters from the response. | |
666 assertEquals("FORGE", bufferContentsToString(readBuffer, 0, 5)); | |
667 // The limit and position should be 5. | |
668 assertEquals(5, readBuffer.limit()); | |
669 assertEquals(5, readBuffer.position()); | |
670 | |
671 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
672 | |
673 // Start reading from position 3. Since the only remaining character | |
674 // from the response is a "T", when the read completes, the buffer | |
675 // should contain "FORTE", with a position() of 4 and a limit() of 5. | |
676 readBuffer.position(3); | |
677 callback.startNextRead(stream, readBuffer); | |
678 callback.waitForNextReadStep(); | |
679 | |
680 // Make sure all three characters of the response have now been read. | |
681 assertEquals("GET", callback.mResponseAsString); | |
682 | |
683 // Check the entire contents of the buffer. Only the third character | |
684 // should have been modified. | |
685 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); | |
686 | |
687 // Make sure position and limit were updated correctly. | |
688 assertEquals(4, readBuffer.position()); | |
689 assertEquals(5, readBuffer.limit()); | |
690 | |
691 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
692 | |
693 // One more read attempt. The request should complete. | |
694 readBuffer.position(1); | |
695 readBuffer.limit(5); | |
696 callback.startNextRead(stream, readBuffer); | |
697 callback.waitForNextReadStep(); | |
698 | |
699 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
700 assertEquals("GET", callback.mResponseAsString); | |
701 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, ""); | |
702 | |
703 // Check that buffer contents were not modified. | |
704 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5)); | |
705 | |
706 // Position should not have been modified, since nothing was read. | |
707 assertEquals(1, readBuffer.position()); | |
708 // Limit should be unchanged as always. | |
709 assertEquals(5, readBuffer.limit()); | |
710 | |
711 assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep); | |
712 | |
713 // Make sure there are no other pending messages, which would trigger | |
714 // asserts in TestBidirectionalCallback. | |
715 testSimpleGet(); | |
716 } | |
717 | |
718 @SmallTest | |
719 @Feature({"Cronet"}) | |
720 @OnlyRunNativeCronet | |
721 public void testBadBuffers() throws Exception { | |
722 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
723 callback.setAutoAdvance(false); | |
724 BidirectionalStream.Builder builder = | |
725 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
726 callback.getExecutor(), mTestFramework.mCronetEngine); | |
727 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
728 stream.start(); | |
729 callback.waitForNextReadStep(); | |
730 | |
731 assertEquals(null, callback.mError); | |
732 assertFalse(callback.isDone()); | |
733 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED, | |
734 callback.mResponseStep); | |
735 | |
736 // Try to read using a full buffer. | |
737 try { | |
738 ByteBuffer readBuffer = ByteBuffer.allocateDirect(4); | |
739 readBuffer.put("full".getBytes()); | |
740 stream.read(readBuffer); | |
741 fail("Exception not thrown"); | |
742 } catch (IllegalArgumentException e) { | |
743 assertEquals("ByteBuffer is already full.", e.getMessage()); | |
744 } | |
745 | |
746 // Try to read using a non-direct buffer. | |
747 try { | |
748 ByteBuffer readBuffer = ByteBuffer.allocate(5); | |
749 stream.read(readBuffer); | |
750 fail("Exception not thrown"); | |
751 } catch (Exception e) { | |
752 assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage ()); | |
753 } | |
754 | |
755 // Finish the stream with a direct ByteBuffer. | |
756 callback.setAutoAdvance(true); | |
757 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
758 stream.read(readBuffer); | |
759 callback.blockForDone(); | |
760 assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); | |
761 assertEquals("GET", callback.mResponseAsString); | |
762 } | |
763 | |
764 private void throwOrCancel(FailureType failureType, ResponseStep failureStep , | |
765 boolean expectResponseInfo, boolean expectError) { | |
766 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
767 callback.setFailure(failureType, failureStep); | |
768 BidirectionalStream.Builder builder = | |
769 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
770 callback.getExecutor(), mTestFramework.mCronetEngine); | |
771 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
772 stream.start(); | |
773 callback.blockForDone(); | |
774 // assertEquals(callback.mResponseStep, failureStep); | |
775 assertTrue(stream.isDone()); | |
776 assertEquals(expectResponseInfo, callback.mResponseInfo != null); | |
777 assertEquals(expectError, callback.mError != null); | |
778 assertEquals(expectError, callback.mOnErrorCalled); | |
779 assertEquals(failureType == FailureType.CANCEL_SYNC | |
780 || failureType == FailureType.CANCEL_ASYNC | |
781 || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE , | |
782 callback.mOnCanceledCalled); | |
783 } | |
784 | |
785 @SmallTest | |
786 @Feature({"Cronet"}) | |
787 @OnlyRunNativeCronet | |
788 public void testFailures() throws Exception { | |
789 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_S ENT, false, false); | |
790 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_ SENT, false, false); | |
791 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE QUEST_HEADERS_SENT, | |
792 false, false); | |
793 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SE NT, false, true); | |
794 | |
795 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, false); | |
796 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED , true, false); | |
797 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE SPONSE_STARTED, | |
798 true, false); | |
799 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, true); | |
800 | |
801 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, t rue, false); | |
802 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED, true, false); | |
803 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE AD_COMPLETED, true, | |
804 false); | |
805 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, tr ue, true); | |
806 } | |
807 | |
808 @SmallTest | |
809 @Feature({"Cronet"}) | |
810 @OnlyRunNativeCronet | |
811 public void testThrowOnSucceeded() { | |
812 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
813 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED); | |
814 BidirectionalStream.Builder builder = | |
815 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
816 callback.getExecutor(), mTestFramework.mCronetEngine); | |
817 BidirectionalStream stream = builder.setHttpMethod("GET").build(); | |
818 stream.start(); | |
819 callback.blockForDone(); | |
820 assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED); | |
821 assertTrue(stream.isDone()); | |
822 assertNotNull(callback.mResponseInfo); | |
823 // Check that error thrown from 'onSucceeded' callback is not reported. | |
824 assertNull(callback.mError); | |
825 assertFalse(callback.mOnErrorCalled); | |
826 } | |
827 | |
828 @SmallTest | |
829 @Feature({"Cronet"}) | |
830 @OnlyRunNativeCronet | |
831 public void testExecutorShutdownBeforeStreamIsDone() { | |
832 // Test that stream is destroyed even if executor is shut down and rejec ts posting tasks. | |
833 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); | |
834 callback.setAutoAdvance(false); | |
835 BidirectionalStream.Builder builder = | |
836 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
837 callback.getExecutor(), mTestFramework.mCronetEngine); | |
838 CronetBidirectionalStream stream = | |
839 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
840 stream.start(); | |
841 callback.waitForNextReadStep(); | |
842 assertFalse(callback.isDone()); | |
843 assertFalse(stream.isDone()); | |
844 | |
845 final ConditionVariable streamDestroyed = new ConditionVariable(false); | |
846 stream.setOnDestroyedCallbackForTesting(new Runnable() { | |
847 @Override | |
848 public void run() { | |
849 streamDestroyed.open(); | |
850 } | |
851 }); | |
852 | |
853 // Shut down the executor, so posting the task will throw an exception. | |
854 callback.shutdownExecutor(); | |
855 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5); | |
856 stream.read(readBuffer); | |
857 // Callback will never be called again because executor is shut down, | |
858 // but stream will be destroyed from network thread. | |
859 streamDestroyed.block(); | |
860 | |
861 assertFalse(callback.isDone()); | |
862 assertTrue(stream.isDone()); | |
863 } | |
864 | |
865 /** | |
866 * Callback that shuts down the engine when the stream has succeeded | |
867 * or failed. | |
868 */ | |
869 private class ShutdownTestBidirectionalStreamCallback extends TestBidirectio nalStreamCallback { | |
870 @Override | |
871 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) { | |
872 mTestFramework.mCronetEngine.shutdown(); | |
873 // Clear mCronetEngine so it doesn't get shut down second time in te arDown(). | |
874 mTestFramework.mCronetEngine = null; | |
875 super.onSucceeded(stream, info); | |
876 } | |
877 | |
878 @Override | |
879 public void onFailed( | |
880 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) { | |
881 mTestFramework.mCronetEngine.shutdown(); | |
882 // Clear mCronetEngine so it doesn't get shut down second time in te arDown(). | |
883 mTestFramework.mCronetEngine = null; | |
884 super.onFailed(stream, info, error); | |
885 } | |
886 | |
887 @Override | |
888 public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) { | |
889 mTestFramework.mCronetEngine.shutdown(); | |
890 // Clear mCronetEngine so it doesn't get shut down second time in te arDown(). | |
891 mTestFramework.mCronetEngine = null; | |
892 super.onCanceled(stream, info); | |
893 } | |
894 } | |
895 | |
896 @SmallTest | |
897 @Feature({"Cronet"}) | |
898 @OnlyRunNativeCronet | |
899 public void testCronetEngineShutdown() throws Exception { | |
900 // Test that CronetEngine cannot be shut down if there are any active st reams. | |
901 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
902 // Block callback when response starts to verify that shutdown fails | |
903 // if there are active streams. | |
904 callback.setAutoAdvance(false); | |
905 BidirectionalStream.Builder builder = | |
906 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
907 callback.getExecutor(), mTestFramework.mCronetEngine); | |
908 CronetBidirectionalStream stream = | |
909 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
910 stream.start(); | |
911 try { | |
912 mTestFramework.mCronetEngine.shutdown(); | |
913 fail("Should throw an exception"); | |
914 } catch (Exception e) { | |
915 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
916 } | |
917 | |
918 callback.waitForNextReadStep(); | |
919 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep); | |
920 try { | |
921 mTestFramework.mCronetEngine.shutdown(); | |
922 fail("Should throw an exception"); | |
923 } catch (Exception e) { | |
924 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
925 } | |
926 callback.startNextRead(stream); | |
927 | |
928 callback.waitForNextReadStep(); | |
929 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep); | |
930 try { | |
931 mTestFramework.mCronetEngine.shutdown(); | |
932 fail("Should throw an exception"); | |
933 } catch (Exception e) { | |
934 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
935 } | |
936 | |
937 // May not have read all the data, in theory. Just enable auto-advance | |
938 // and finish the request. | |
939 callback.setAutoAdvance(true); | |
940 callback.startNextRead(stream); | |
941 callback.blockForDone(); | |
942 } | |
943 | |
944 @SmallTest | |
945 @Feature({"Cronet"}) | |
946 @OnlyRunNativeCronet | |
947 public void testCronetEngineShutdownAfterStreamFailure() throws Exception { | |
948 // Test that CronetEngine can be shut down after stream reports a failur e. | |
949 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
950 BidirectionalStream.Builder builder = | |
951 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
952 callback.getExecutor(), mTestFramework.mCronetEngine); | |
953 CronetBidirectionalStream stream = | |
954 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
955 stream.start(); | |
956 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLET ED); | |
957 callback.blockForDone(); | |
958 assertTrue(callback.mOnErrorCalled); | |
959 assertNull(mTestFramework.mCronetEngine); | |
960 } | |
961 | |
962 @SmallTest | |
963 @Feature({"Cronet"}) | |
964 @OnlyRunNativeCronet | |
965 public void testCronetEngineShutdownAfterStreamCancel() throws Exception { | |
966 // Test that CronetEngine can be shut down after stream is canceled. | |
967 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback(); | |
968 BidirectionalStream.Builder builder = | |
969 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback, | |
970 callback.getExecutor(), mTestFramework.mCronetEngine); | |
971 CronetBidirectionalStream stream = | |
972 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ; | |
973 | |
974 // Block callback when response starts to verify that shutdown fails | |
975 // if there are active requests. | |
976 callback.setAutoAdvance(false); | |
977 stream.start(); | |
978 try { | |
979 mTestFramework.mCronetEngine.shutdown(); | |
980 fail("Should throw an exception"); | |
981 } catch (Exception e) { | |
982 assertEquals("Cannot shutdown with active requests.", e.getMessage() ); | |
983 } | |
984 callback.waitForNextReadStep(); | |
985 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep); | |
986 stream.cancel(); | |
987 callback.blockForDone(); | |
988 assertTrue(callback.mOnCanceledCalled); | |
989 assertNull(mTestFramework.mCronetEngine); | |
990 } | |
991 | |
992 // Returns the contents of byteBuffer, from its position() to its limit(), | |
993 // as a String. Does not modify byteBuffer's position(). | |
994 private static String bufferContentsToString(ByteBuffer byteBuffer, int star t, int end) { | |
995 // Use a duplicate to avoid modifying byteBuffer. | |
996 ByteBuffer duplicate = byteBuffer.duplicate(); | |
997 duplicate.position(start); | |
998 duplicate.limit(end); | |
999 byte[] contents = new byte[duplicate.remaining()]; | |
1000 duplicate.get(contents); | |
1001 return new String(contents); | |
120 } | 1002 } |
121 } | 1003 } |
OLD | NEW |