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

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: Destroy the native adapter instead of cancel if can't post task to executor. 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 */
27 @OnlyRunNativeCronet
20 public class BidirectionalStreamTest extends CronetTestBase { 28 public class BidirectionalStreamTest extends CronetTestBase {
29 private static final String CERT_USED = "quic_test.example.com.crt";
30 private static final String KEY_USED = "quic_test.example.com.key";
pauljensen 2016/01/19 16:03:40 Please move these to a shared location, perhaps Qu
mef 2016/01/20 15:37:41 Done.
31 private static final String[] CERTS_USED = {CERT_USED};
32
21 private CronetTestFramework mTestFramework; 33 private CronetTestFramework mTestFramework;
34 // URL used for base tests.
35 private static final String TEST_URL = "https://127.0.0.1:8443";
pauljensen 2016/01/19 16:03:40 I wonder if this should be constructed via some Ht
mef 2016/01/20 15:37:41 Done.
22 36
23 @Override 37 @Override
24 protected void setUp() throws Exception { 38 protected void setUp() throws Exception {
25 super.setUp(); 39 super.setUp();
26 mTestFramework = startCronetTestFramework(); 40 // Load library first to create MockCertVerifier.
41 System.loadLibrary("cronet_tests");
42
43 CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
44 builder.setMockCertVerifierForTesting(MockCertVerifier.createMockCertVer ifier(CERTS_USED));
pauljensen 2016/01/19 16:03:40 I feel like this should be moved to a convenience
mef 2016/01/20 15:37:41 Done.
45
46 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n ull, builder);
27 assertTrue(NativeTestServer.startNativeTestServer(getContext())); 47 assertTrue(NativeTestServer.startNativeTestServer(getContext()));
48 assertTrue(Http2TestServer.startHttp2TestServer(getContext(), CERT_USED, KEY_USED));
28 // Add url interceptors after native application context is initialized. 49 // Add url interceptors after native application context is initialized.
29 MockUrlRequestJobFactory.setUp(); 50 MockUrlRequestJobFactory.setUp();
30 } 51 }
31 52
32 @Override 53 @Override
33 protected void tearDown() throws Exception { 54 protected void tearDown() throws Exception {
55 assertTrue(Http2TestServer.shutdownHttp2TestServer());
34 NativeTestServer.shutdownNativeTestServer(); 56 NativeTestServer.shutdownNativeTestServer();
35 mTestFramework.mCronetEngine.shutdown(); 57 if (mTestFramework.mCronetEngine != null) {
58 mTestFramework.mCronetEngine.shutdown();
59 }
36 super.tearDown(); 60 super.tearDown();
37 } 61 }
38 62
39 private class TestBidirectionalStreamCallback extends BidirectionalStream.Ca llback { 63 private TestBidirectionalStreamCallback startAndWaitForComplete(String url) throws Exception {
40 // Executor Service for Cronet callbacks. 64 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
41 private final ExecutorService mExecutorService =
42 Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
43 private Thread mExecutorThread;
44 65
45 private class ExecutorThreadFactory implements ThreadFactory { 66 // Create stream.
46 public Thread newThread(Runnable r) { 67 BidirectionalStream stream =
47 mExecutorThread = new Thread(r); 68 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
48 return mExecutorThread; 69 mTestFramework.mCronetEngine)
49 } 70 .setHttpMethod("GET")
71 .build();
72 stream.start();
73 callback.blockForDone();
74 assertTrue(stream.isDone());
75 return callback;
76 }
77
78 private void checkResponseInfo(UrlResponseInfo responseInfo, String expected Url,
79 int expectedHttpStatusCode, String expectedHttpStatusText) {
80 assertEquals(expectedUrl, responseInfo.getUrl());
81 assertEquals(
82 expectedUrl, responseInfo.getUrlChain().get(responseInfo.getUrlC hain().size() - 1));
83 assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode());
84 assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText());
85 assertFalse(responseInfo.wasCached());
86 assertTrue(responseInfo.toString().length() > 0);
87 }
88
89 private static String makeLongString(String base, int repetition) {
90 StringBuilder builder = new StringBuilder(base.length() * repetition);
91 for (int i = 0; i < repetition; ++i) {
92 builder.append(i);
93 builder.append(base);
50 } 94 }
51 95 return builder.toString();
52 @Override
53 public void onRequestHeadersSent(BidirectionalStream stream) {}
54
55 @Override
56 public void onResponseHeadersReceived(BidirectionalStream stream, UrlRes ponseInfo info) {}
57
58 @Override
59 public void onReadCompleted(
60 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf fer) {}
61
62 @Override
63 public void onWriteCompleted(
64 BidirectionalStream stream, UrlResponseInfo info, ByteBuffer buf fer) {}
65
66 @Override
67 public void onResponseTrailersReceived(BidirectionalStream stream, UrlRe sponseInfo info,
68 UrlResponseInfo.HeaderBlock trailers) {}
69
70 @Override
71 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) {}
72
73 @Override
74 public void onFailed(
75 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) {}
76
77 @Override
78 public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {}
79
80 Executor getExecutor() {
81 return mExecutorService;
82 }
83 } 96 }
84 97
85 @SmallTest 98 @SmallTest
86 @Feature({"Cronet"}) 99 @Feature({"Cronet"})
87 public void testBuilderChecks() throws Exception { 100 public void testBuilderChecks() throws Exception {
88 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback(); 101 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
89 try { 102 try {
90 new BidirectionalStream.Builder( 103 new BidirectionalStream.Builder(
91 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine); 104 null, callback, callback.getExecutor(), mTestFramework.mCron etEngine);
92 fail("URL not null-checked"); 105 fail("URL not null-checked");
(...skipping 18 matching lines...) Expand all
111 new BidirectionalStream.Builder( 124 new BidirectionalStream.Builder(
112 NativeTestServer.getRedirectURL(), callback, callback.getExe cutor(), null); 125 NativeTestServer.getRedirectURL(), callback, callback.getExe cutor(), null);
113 fail("CronetEngine not null-checked"); 126 fail("CronetEngine not null-checked");
114 } catch (NullPointerException e) { 127 } catch (NullPointerException e) {
115 assertEquals("CronetEngine is required.", e.getMessage()); 128 assertEquals("CronetEngine is required.", e.getMessage());
116 } 129 }
117 // Verify successful creation doesn't throw. 130 // Verify successful creation doesn't throw.
118 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb ack, 131 new BidirectionalStream.Builder(NativeTestServer.getRedirectURL(), callb ack,
119 callback.getExecutor(), mTestFramework.mCronetEngine); 132 callback.getExecutor(), mTestFramework.mCronetEngine);
120 } 133 }
134
135 @SmallTest
136 @Feature({"Cronet"})
137 public void testFailPlainHttp() throws Exception {
138 String url = NativeTestServer.getEchoMethodURL();
139 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
140 assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_ SCHEME",
141 callback.mError.getMessage());
142 }
143
144 @SmallTest
145 @Feature({"Cronet"})
146 public void testSimpleGet() throws Exception {
147 String url = Http2TestServer.getEchoMethodUrl();
148 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
149 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
150 // Default method is 'GET'.
151 assertEquals("GET", callback.mResponseAsString);
152 UrlResponseInfo urlResponseInfo =
153 createUrlResponseInfo(new String[] {url}, "", 200, 27, ":status" , "200");
154 assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
155 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, "");
156 }
157
158 UrlResponseInfo createUrlResponseInfo(
159 String[] urls, String message, int statusCode, int receivedBytes, St ring... headers) {
160 ArrayList<Map.Entry<String, String>> headersList = new ArrayList<>();
161 for (int i = 0; i < headers.length; i += 2) {
162 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String> (
163 headers[i], headers[i + 1]));
164 }
165 UrlResponseInfo unknown = new UrlResponseInfo(
166 Arrays.asList(urls), statusCode, message, headersList, false, "h 2", null);
167 unknown.setReceivedBytesCount(receivedBytes);
168 return unknown;
169 }
170
171 @SmallTest
172 @Feature({"Cronet"})
173 public void testSimpleHead() throws Exception {
174 String url = Http2TestServer.getEchoMethodUrl();
175 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
176
177 // Create stream.
178 BidirectionalStream stream =
179 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
180 mTestFramework.mCronetEngine)
181 .setHttpMethod("HEAD")
182 .build();
183 stream.start();
184 callback.blockForDone();
185 assertTrue(stream.isDone());
186 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
187 assertEquals("HEAD", callback.mResponseAsString);
188 UrlResponseInfo urlResponseInfo =
189 createUrlResponseInfo(new String[] {url}, "", 200, 28, ":status" , "200");
190 assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
191 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, "");
192 }
193
194 @SmallTest
195 @Feature({"Cronet"})
196 public void testSimplePost() throws Exception {
197 String url = Http2TestServer.getEchoStreamUrl();
198 mTestFramework.startNetLog();
199
200 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
201 callback.addWriteData("Test String".getBytes());
202 callback.addWriteData("1234567890".getBytes());
203 callback.addWriteData("woot!".getBytes());
204
205 // Create stream.
206 BidirectionalStream stream =
207 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
208 mTestFramework.mCronetEngine)
209 .addHeader("foo", "bar")
210 .addHeader("Content-Type", "zebra")
211 .build();
212 stream.start();
213 callback.blockForDone();
214 assertTrue(stream.isDone());
215
216 mTestFramework.stopNetLog();
217
218 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
219 assertEquals("Test String1234567890woot!", callback.mResponseAsString);
220 assertEquals("bar", callback.mResponseInfo.getAllHeaders().get("echo-foo ").get(0));
221 assertEquals(
222 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0));
223 }
224
225 @SmallTest
226 @Feature({"Cronet"})
227 public void testSetHttpMethod() throws Exception {
228 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
229 callback.addWriteData("Put This Data!".getBytes());
230
231 String methodName = "PUT";
232 BidirectionalStream.Builder builder = new BidirectionalStream.Builder(
233 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine);
234 // Try to set 'null' method.
235 try {
236 builder.setHttpMethod(null);
237 fail("Exception not thrown");
238 } catch (NullPointerException e) {
239 assertEquals("Method is required.", e.getMessage());
240 }
241
242 builder.setHttpMethod(methodName);
243 builder.build().start();
244 callback.blockForDone();
245 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
246 assertEquals("Put This Data!", callback.mResponseAsString);
247 assertEquals("PUT", callback.mResponseInfo.getAllHeaders().get("echo-met hod").get(0));
248 }
249
250 @SmallTest
251 @Feature({"Cronet"})
252 public void testBadMethod() throws Exception {
253 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
254 BidirectionalStream.Builder builder = new BidirectionalStream.Builder(
255 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine);
256 try {
257 builder.setHttpMethod("bad:method!");
258 builder.build().start();
259 fail("IllegalArgumentException not thrown.");
260 } catch (IllegalArgumentException e) {
261 assertEquals("Invalid http method bad:method!", e.getMessage());
262 }
263 }
264
265 @SmallTest
266 @Feature({"Cronet"})
267 public void testBadHeaderName() throws Exception {
268 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
269 BidirectionalStream.Builder builder = new BidirectionalStream.Builder(
270 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine);
271 try {
272 builder.addHeader("header:name", "headervalue");
273 builder.build().start();
274 fail("IllegalArgumentException not thrown.");
275 } catch (IllegalArgumentException e) {
276 assertEquals("Invalid header header:name=headervalue", e.getMessage( ));
277 }
278 }
279
280 @SmallTest
281 @Feature({"Cronet"})
282 public void testBadHeaderValue() throws Exception {
283 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
284 BidirectionalStream.Builder builder = new BidirectionalStream.Builder(
285 TEST_URL, callback, callback.getExecutor(), mTestFramework.mCron etEngine);
286 try {
287 builder.addHeader("headername", "bad header\r\nvalue");
288 builder.build().start();
289 fail("IllegalArgumentException not thrown.");
290 } catch (IllegalArgumentException e) {
291 assertEquals("Invalid header headername=bad header\r\nvalue", e.getM essage());
292 }
293 }
294
295 @SmallTest
296 @Feature({"Cronet"})
297 public void testAddHeader() throws Exception {
298 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
299 String headerName = "header-name";
300 String headerValue = "header-value";
301 BidirectionalStream.Builder builder =
302 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (headerName),
303 callback, callback.getExecutor(), mTestFramework.mCronet Engine);
304
305 builder.addHeader(headerName, headerValue);
306 builder.setHttpMethod("GET");
307 builder.build().start();
308 callback.blockForDone();
309 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
310 assertEquals(headerValue, callback.mResponseAsString);
311 }
312
313 @SmallTest
314 @Feature({"Cronet"})
315 public void testMultiRequestHeaders() throws Exception {
316 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
317 String headerName = "header-name";
318 String headerValue1 = "header-value1";
319 String headerValue2 = "header-value2";
320 BidirectionalStream.Builder builder =
321 new BidirectionalStream.Builder(Http2TestServer.getEchoAllHeader sUrl(), callback,
322 callback.getExecutor(), mTestFramework.mCronetEngine);
323 builder.addHeader(headerName, headerValue1);
324 builder.addHeader(headerName, headerValue2);
325 builder.setHttpMethod("GET");
326 builder.build().start();
327 callback.blockForDone();
328 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
329 String headers = callback.mResponseAsString;
330 Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n");
331 Matcher matcher = pattern.matcher(headers);
332 List<String> actualValues = new ArrayList<String>();
333 while (matcher.find()) {
334 actualValues.add(matcher.group(1));
335 }
336 assertEquals(1, actualValues.size());
337 assertEquals("header-value2", actualValues.get(0));
338 }
339
340 @SmallTest
341 @Feature({"Cronet"})
342 public void testEchoTrailers() throws Exception {
343 mTestFramework.startNetLog();
344
345 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
346 String headerName = "header-name";
347 String headerValue = "header-value";
348 BidirectionalStream.Builder builder =
349 new BidirectionalStream.Builder(Http2TestServer.getEchoTrailersU rl(), callback,
350 callback.getExecutor(), mTestFramework.mCronetEngine);
351 builder.addHeader(headerName, headerValue);
352 builder.setHttpMethod("GET");
353 builder.build().start();
354 callback.blockForDone();
355 mTestFramework.stopNetLog();
pauljensen 2016/01/19 16:03:40 what's the netLog for?
mef 2016/01/20 15:37:41 To see the trailers? Gone.
356
357 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
358 assertNotNull(callback.mTrailers);
359 assertEquals(headerValue, callback.mTrailers.getAsMap().get("echo-header -name").get(0));
360 }
361
362 @SmallTest
363 @Feature({"Cronet"})
364 public void testCustomUserAgent() throws Exception {
365 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
366 String userAgentName = "User-Agent";
367 String userAgentValue = "User-Agent-Value";
368 BidirectionalStream.Builder builder =
369 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (userAgentName),
370 callback, callback.getExecutor(), mTestFramework.mCronet Engine);
371 builder.setHttpMethod("GET");
372 builder.addHeader(userAgentName, userAgentValue);
373 builder.build().start();
374 callback.blockForDone();
375 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
376 assertEquals(userAgentValue, callback.mResponseAsString);
377 }
378
379 @SmallTest
380 @Feature({"Cronet"})
381 public void testEchoStream() throws Exception {
382 String url = Http2TestServer.getEchoStreamUrl();
383 mTestFramework.startNetLog();
384
385 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
386 String[] testData = {"Test String", makeLongString("1234567890", 50000), "woot!"};
387 StringBuilder stringData = new StringBuilder();
388 for (String writeData : testData) {
389 callback.addWriteData(writeData.getBytes());
390 stringData.append(writeData);
391 }
392
393 // Create stream.
394 BidirectionalStream stream =
395 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
396 mTestFramework.mCronetEngine)
397 .addHeader("foo", "Value with Spaces")
398 .addHeader("Content-Type", "zebra")
399 .build();
400 stream.start();
401 callback.blockForDone();
402 assertTrue(stream.isDone());
403
404 mTestFramework.stopNetLog();
405
406 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
407 assertEquals(stringData.toString(), callback.mResponseAsString);
408 assertEquals(
409 "Value with Spaces", callback.mResponseInfo.getAllHeaders().get( "echo-foo").get(0));
410 assertEquals(
411 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0));
412 }
413
414 @SmallTest
415 @Feature({"Cronet"})
416 public void testEchoStreamStepByStep() throws Exception {
417 String url = Http2TestServer.getEchoStreamUrl();
418 mTestFramework.startNetLog();
419
420 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
421 callback.setAutoAdvance(false);
422
423 String[] testData = {"a", "bb", "ccc", "Test String", "1234567890", "woo t!"};
424 StringBuilder stringData = new StringBuilder();
425 for (String writeData : testData) {
426 callback.addWriteData(writeData.getBytes());
427 stringData.append(writeData);
428 }
429
430 // Create stream.
431 BidirectionalStream stream =
432 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
433 mTestFramework.mCronetEngine)
434 .build();
435 stream.start();
436 callback.waitForNextWriteStep();
437 callback.waitForNextReadStep();
438
439 for (String expected : testData) {
440 // Write next chunk of test data.
441 callback.startNextWrite(stream);
442 callback.waitForNextWriteStep();
443
444 // Read next chunk of test data.
445 ByteBuffer readBuffer = ByteBuffer.allocateDirect(100);
446 callback.startNextRead(stream, readBuffer);
447 callback.waitForNextReadStep();
448 assertEquals(expected.length(), readBuffer.position());
449 assertFalse(stream.isDone());
450 }
451
452 callback.setAutoAdvance(true);
453 callback.startNextRead(stream);
454 callback.blockForDone();
455 assertTrue(stream.isDone());
456
457 mTestFramework.stopNetLog();
pauljensen 2016/01/19 16:03:40 ditto
mef 2016/01/20 15:37:40 Done.
458
459 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
460 assertEquals(stringData.toString(), callback.mResponseAsString);
461 }
462
463 /**
464 * Checks that the buffer is updated correctly, when starting at an offset.
465 */
466 @SmallTest
467 @Feature({"Cronet"})
468 public void testSimpleGetBufferUpdates() throws Exception {
469 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
470 callback.setAutoAdvance(false);
471 // Since themethod is "GET", the expected response body is also "GET".
pauljensen 2016/01/19 16:03:41 themethod->the method
mef 2016/01/20 15:37:41 Done.
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 public void testBadBuffers() throws Exception {
558 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
559 callback.setAutoAdvance(false);
560 BidirectionalStream.Builder builder =
561 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
562 callback.getExecutor(), mTestFramework.mCronetEngine);
563 BidirectionalStream stream = builder.setHttpMethod("GET").build();
564 stream.start();
565 callback.waitForNextReadStep();
566
567 assertEquals(null, callback.mError);
568 assertFalse(callback.isDone());
569 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED,
570 callback.mResponseStep);
571
572 // Try to read using a full buffer.
573 try {
574 ByteBuffer readBuffer = ByteBuffer.allocateDirect(4);
575 readBuffer.put("full".getBytes());
576 stream.read(readBuffer);
577 fail("Exception not thrown");
578 } catch (IllegalArgumentException e) {
579 assertEquals("ByteBuffer is already full.", e.getMessage());
580 }
581
582 // Try to read using a non-direct buffer.
583 try {
584 ByteBuffer readBuffer = ByteBuffer.allocate(5);
585 stream.read(readBuffer);
586 fail("Exception not thrown");
587 } catch (Exception e) {
588 assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage ());
589 }
590
591 // Finish the stream with a direct ByteBuffer.
592 callback.setAutoAdvance(true);
593 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
594 stream.read(readBuffer);
595 callback.blockForDone();
596 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
597 assertEquals("GET", callback.mResponseAsString);
598 }
599
600 private void throwOrCancel(FailureType failureType, ResponseStep failureStep ,
601 boolean expectResponseInfo, boolean expectError) {
602 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
603 callback.setFailure(failureType, failureStep);
604 BidirectionalStream.Builder builder =
605 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
606 callback.getExecutor(), mTestFramework.mCronetEngine);
607 BidirectionalStream stream = builder.setHttpMethod("GET").build();
608 stream.start();
609 callback.blockForDone();
610 assertEquals(callback.mResponseStep, failureStep);
611 assertTrue(stream.isDone());
612 assertEquals(expectResponseInfo, callback.mResponseInfo != null);
613 assertEquals(expectError, callback.mError != null);
614 assertEquals(expectError, callback.mOnErrorCalled);
615 assertEquals(failureType == FailureType.CANCEL_SYNC
616 || failureType == FailureType.CANCEL_ASYNC
617 || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE ,
618 callback.mOnCanceledCalled);
619 }
620
621 @SmallTest
622 @Feature({"Cronet"})
623 public void testFailures() throws Exception {
624 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_S ENT, false, false);
625 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_ SENT, false, false);
626 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE QUEST_HEADERS_SENT,
627 false, false);
628 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SE NT, false, true);
629
630 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, false);
631 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED , true, false);
632 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE SPONSE_STARTED,
633 true, false);
634 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, true);
635
636 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, t rue, false);
637 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED, true, false);
638 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE AD_COMPLETED, true,
639 false);
640 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, tr ue, true);
641 }
642
643 @SmallTest
644 @Feature({"Cronet"})
645 public void testThrowOnSucceeded() {
646 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
647 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED);
648 BidirectionalStream.Builder builder =
649 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
650 callback.getExecutor(), mTestFramework.mCronetEngine);
651 BidirectionalStream stream = builder.setHttpMethod("GET").build();
652 stream.start();
653 callback.blockForDone();
654 assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED);
655 assertTrue(stream.isDone());
656 assertNotNull(callback.mResponseInfo);
657 assertNull(callback.mError);
658 assertFalse(callback.mOnErrorCalled);
659 }
660
661 @SmallTest
662 @Feature({"Cronet"})
663 public void testExecutorShutdown() {
664 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
665
666 callback.setAutoAdvance(false);
667 BidirectionalStream.Builder builder =
668 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
669 callback.getExecutor(), mTestFramework.mCronetEngine);
670 CronetBidirectionalStream stream =
671 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
672 stream.start();
673 callback.waitForNextReadStep();
674 assertFalse(callback.isDone());
675 assertFalse(stream.isDone());
676
677 final ConditionVariable requestDestroyed = new ConditionVariable(false);
678 stream.setOnDestroyedCallbackForTesting(new Runnable() {
679 @Override
680 public void run() {
681 requestDestroyed.open();
682 }
683 });
684
685 // Shutdown the executor, so posting the task will throw an exception.
686 callback.shutdownExecutor();
687 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
688 stream.read(readBuffer);
689 // Callback will never be called again because executor is shutdown,
690 // but stream will be destroyed from network thread.
691 requestDestroyed.block();
692
693 assertFalse(callback.isDone());
694 assertTrue(stream.isDone());
695 }
696
697 /**
698 * Callback that shutdowns the engine when the stream has succeeded
699 * or failed.
700 */
701 class ShutdownTestBidirectionalStreamCallback extends TestBidirectionalStrea mCallback {
702 @Override
703 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) {
704 mTestFramework.mCronetEngine.shutdown();
705 // Clear mCronetEngine so it doesn't get shutdown second time in tea rDown().
706 mTestFramework.mCronetEngine = null;
707 super.onSucceeded(stream, info);
708 }
709
710 @Override
711 public void onFailed(
712 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) {
713 mTestFramework.mCronetEngine.shutdown();
714 // Clear mCronetEngine so it doesn't get shutdown second time in tea rDown().
715 mTestFramework.mCronetEngine = null;
716 super.onFailed(stream, info, error);
717 }
718 }
719
720 @SmallTest
721 @Feature({"Cronet"})
722 public void testShutdown() throws Exception {
723 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
724 // Block callback when response starts to verify that shutdown fails
725 // if there are active stream.
726 callback.setAutoAdvance(false);
727 BidirectionalStream.Builder builder =
728 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
729 callback.getExecutor(), mTestFramework.mCronetEngine);
730 CronetBidirectionalStream stream =
731 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
732 stream.start();
733 try {
734 mTestFramework.mCronetEngine.shutdown();
735 fail("Should throw an exception");
736 } catch (Exception e) {
737 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
738 }
739
740 callback.waitForNextReadStep();
741 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
742 try {
743 mTestFramework.mCronetEngine.shutdown();
744 fail("Should throw an exception");
745 } catch (Exception e) {
746 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
747 }
748 callback.startNextRead(stream);
749
750 callback.waitForNextReadStep();
751 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
752 try {
753 mTestFramework.mCronetEngine.shutdown();
754 fail("Should throw an exception");
755 } catch (Exception e) {
756 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
757 }
758
759 // May not have read all the data, in theory. Just enable auto-advance
760 // and finish the request.
761 callback.setAutoAdvance(true);
762 callback.startNextRead(stream);
763 callback.blockForDone();
764 }
765
766 @SmallTest
767 @Feature({"Cronet"})
768 public void testShutdownAfterError() throws Exception {
769 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
770 BidirectionalStream.Builder builder =
771 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
772 callback.getExecutor(), mTestFramework.mCronetEngine);
773 CronetBidirectionalStream stream =
774 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
775 stream.start();
776 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLET ED);
777 callback.blockForDone();
778 assertTrue(callback.mOnErrorCalled);
779 }
780
781 @SmallTest
782 @Feature({"Cronet"})
783 public void testShutdownAfterCancel() throws Exception {
784 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
785 BidirectionalStream.Builder builder =
786 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
787 callback.getExecutor(), mTestFramework.mCronetEngine);
788 CronetBidirectionalStream stream =
789 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
790
791 // Block callback when response starts to verify that shutdown fails
792 // if there are active requests.
793 callback.setAutoAdvance(false);
794 stream.start();
795 try {
796 mTestFramework.mCronetEngine.shutdown();
797 fail("Should throw an exception");
798 } catch (Exception e) {
799 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
800 }
801 callback.waitForNextReadStep();
802 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
803 stream.cancel();
804 }
pauljensen 2016/01/19 16:03:40 it doesn't look like we call shutdown() after canc
mef 2016/01/20 15:37:41 We do in tearDown(), but I've added onCanceled() o
805
806 // Returns the contents of byteBuffer, from its position() to its limit(),
807 // as a String. Does not modify byteBuffer's position().
808 private String bufferContentsToString(ByteBuffer byteBuffer, int start, int end) {
809 // Use a duplicate to avoid modifying byteBuffer.
810 ByteBuffer duplicate = byteBuffer.duplicate();
811 duplicate.position(start);
812 duplicate.limit(end);
813 byte[] contents = new byte[duplicate.remaining()];
814 duplicate.get(contents);
815 return new String(contents);
816 }
121 } 817 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698