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