Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java

Issue 1412243012: Initial implementation of CronetBidirectionalStream. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Self review. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698