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

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: Log the exception. 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 {
xunjieli 2016/01/27 16:16:38 Only used in two tests. Don't think we will use in
mef 2016/01/27 19:06:47 Done.
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) {
xunjieli 2016/01/27 16:16:38 nit: consider s/make/create to be consistent with
mef 2016/01/27 19:06:47 Done.
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;
xunjieli 2016/01/27 16:16:38 nit: I am not sure why the variable is called "unk
mef 2016/01/27 19:06:47 Done.
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 BidirectionalStream.Builder builder =
119 callback.getExecutor(), mTestFramework.mCronetEngine); 134 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
135 callback.getExecutor(), mTestFramework.mCronetEngine);
136 try {
137 builder.addHeader(null, "value");
138 fail("Header name is not null-checked");
139 } catch (NullPointerException e) {
140 assertEquals("Invalid header name.", e.getMessage());
141 }
142 try {
143 builder.addHeader("name", null);
144 fail("Header value is not null-checked");
145 } catch (NullPointerException e) {
146 assertEquals("Invalid header value.", e.getMessage());
147 }
148 }
149
150 @SmallTest
151 @Feature({"Cronet"})
152 @OnlyRunNativeCronet
153 public void testFailPlainHttp() throws Exception {
154 String url = "http://example.com";
155 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
156 assertEquals("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_ SCHEME",
157 callback.mError.getMessage());
158 }
159
160 @SmallTest
161 @Feature({"Cronet"})
162 @OnlyRunNativeCronet
163 public void testSimpleGet() throws Exception {
164 String url = Http2TestServer.getEchoMethodUrl();
165 TestBidirectionalStreamCallback callback = startAndWaitForComplete(url);
166 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
167 // Default method is 'GET'.
168 assertEquals("GET", callback.mResponseAsString);
169 UrlResponseInfo urlResponseInfo =
170 createUrlResponseInfo(new String[] {url}, "", 200, 27, ":status" , "200");
171 assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
172 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, "");
173 }
174
175 @SmallTest
176 @Feature({"Cronet"})
177 @OnlyRunNativeCronet
178 public void testSimpleHead() throws Exception {
179 String url = Http2TestServer.getEchoMethodUrl();
180 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
181 // Create stream.
182 BidirectionalStream stream =
183 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
184 mTestFramework.mCronetEngine)
185 .setHttpMethod("HEAD")
186 .build();
187 stream.start();
188 callback.blockForDone();
189 assertTrue(stream.isDone());
190 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
191 assertEquals("HEAD", callback.mResponseAsString);
192 UrlResponseInfo urlResponseInfo =
193 createUrlResponseInfo(new String[] {url}, "", 200, 28, ":status" , "200");
194 assertResponseEquals(urlResponseInfo, callback.mResponseInfo);
195 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, "");
196 }
197
198 @SmallTest
199 @Feature({"Cronet"})
200 @OnlyRunNativeCronet
201 public void testSimplePost() throws Exception {
202 String url = Http2TestServer.getEchoStreamUrl();
203 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
204 callback.addWriteData("Test String".getBytes());
205 callback.addWriteData("1234567890".getBytes());
206 callback.addWriteData("woot!".getBytes());
207 // Create stream.
208 BidirectionalStream stream =
209 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
210 mTestFramework.mCronetEngine)
211 .addHeader("foo", "bar")
212 .addHeader("empty", "")
213 .addHeader("Content-Type", "zebra")
214 .build();
215 stream.start();
216 callback.blockForDone();
217 assertTrue(stream.isDone());
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("", callback.mResponseInfo.getAllHeaders().get("echo-empty" ).get(0));
222 assertEquals(
223 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0));
224 }
225
226 @SmallTest
227 @Feature({"Cronet"})
228 @OnlyRunNativeCronet
229 public void testSetHttpMethod() throws Exception {
xunjieli 2016/01/27 16:16:38 Suggest naming this test as testSimplePut. And mov
mef 2016/01/27 19:06:47 Done.
230 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
231 callback.addWriteData("Put This Data!".getBytes());
232 String methodName = "PUT";
233 BidirectionalStream.Builder builder =
234 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
235 callback.getExecutor(), mTestFramework.mCronetEngine);
236 // Try to set 'null' method.
237 try {
238 builder.setHttpMethod(null);
239 fail("Exception not thrown");
240 } catch (NullPointerException e) {
241 assertEquals("Method is required.", e.getMessage());
242 }
243 builder.setHttpMethod(methodName);
244 builder.build().start();
245 callback.blockForDone();
246 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
247 assertEquals("Put This Data!", callback.mResponseAsString);
248 assertEquals(methodName, callback.mResponseInfo.getAllHeaders().get("ech o-method").get(0));
249 }
250
251 @SmallTest
252 @Feature({"Cronet"})
253 @OnlyRunNativeCronet
254 public void testBadMethod() throws Exception {
255 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
256 BidirectionalStream.Builder builder =
257 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
258 callback.getExecutor(), mTestFramework.mCronetEngine);
259 try {
260 builder.setHttpMethod("bad:method!");
261 builder.build().start();
262 fail("IllegalArgumentException not thrown.");
263 } catch (IllegalArgumentException e) {
264 assertEquals("Invalid http method bad:method!", e.getMessage());
265 }
266 }
267
268 @SmallTest
269 @Feature({"Cronet"})
270 @OnlyRunNativeCronet
271 public void testBadHeaderName() throws Exception {
272 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
273 BidirectionalStream.Builder builder =
274 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
275 callback.getExecutor(), mTestFramework.mCronetEngine);
276 try {
277 builder.addHeader("goodheader1", "headervalue");
278 builder.addHeader("header:name", "headervalue");
279 builder.addHeader("goodheader2", "headervalue");
280 builder.build().start();
281 fail("IllegalArgumentException not thrown.");
282 } catch (IllegalArgumentException e) {
283 assertEquals("Invalid header header:name=headervalue", e.getMessage( ));
284 }
285 }
286
287 @SmallTest
288 @Feature({"Cronet"})
289 @OnlyRunNativeCronet
290 public void testBadHeaderValue() throws Exception {
291 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
292 BidirectionalStream.Builder builder =
293 new BidirectionalStream.Builder(Http2TestServer.getServerUrl(), callback,
294 callback.getExecutor(), mTestFramework.mCronetEngine);
295 try {
296 builder.addHeader("headername", "bad header\r\nvalue");
297 builder.build().start();
298 fail("IllegalArgumentException not thrown.");
299 } catch (IllegalArgumentException e) {
300 assertEquals("Invalid header headername=bad header\r\nvalue", e.getM essage());
301 }
302 }
303
304 @SmallTest
305 @Feature({"Cronet"})
306 @OnlyRunNativeCronet
307 public void testAddHeader() throws Exception {
308 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
309 String headerName = "header-name";
310 String headerValue = "header-value";
311 BidirectionalStream.Builder builder =
312 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (headerName),
313 callback, callback.getExecutor(), mTestFramework.mCronet Engine);
314 builder.addHeader(headerName, headerValue);
315 builder.setHttpMethod("GET");
316 builder.build().start();
317 callback.blockForDone();
318 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
319 assertEquals(headerValue, callback.mResponseAsString);
320 }
321
322 @SmallTest
323 @Feature({"Cronet"})
324 @OnlyRunNativeCronet
325 public void testMultiRequestHeaders() throws Exception {
326 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
327 String headerName = "header-name";
328 String headerValue1 = "header-value1";
329 String headerValue2 = "header-value2";
330 BidirectionalStream.Builder builder =
331 new BidirectionalStream.Builder(Http2TestServer.getEchoAllHeader sUrl(), callback,
332 callback.getExecutor(), mTestFramework.mCronetEngine);
333 builder.addHeader(headerName, headerValue1);
334 builder.addHeader(headerName, headerValue2);
335 builder.setHttpMethod("GET");
336 builder.build().start();
337 callback.blockForDone();
338 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
339 String headers = callback.mResponseAsString;
340 Pattern pattern = Pattern.compile(headerName + ":\\s(.*)\\r\\n");
341 Matcher matcher = pattern.matcher(headers);
342 List<String> actualValues = new ArrayList<String>();
343 while (matcher.find()) {
344 actualValues.add(matcher.group(1));
345 }
346 assertEquals(1, actualValues.size());
347 assertEquals("header-value2", actualValues.get(0));
348 }
349
350 @SmallTest
351 @Feature({"Cronet"})
352 @OnlyRunNativeCronet
353 public void testEchoTrailers() throws Exception {
354 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
355 String headerName = "header-name";
356 String headerValue = "header-value";
357 BidirectionalStream.Builder builder =
358 new BidirectionalStream.Builder(Http2TestServer.getEchoTrailersU rl(), callback,
359 callback.getExecutor(), mTestFramework.mCronetEngine);
360 builder.addHeader(headerName, headerValue);
361 builder.setHttpMethod("GET");
362 builder.build().start();
363 callback.blockForDone();
364 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
365 assertNotNull(callback.mTrailers);
366 assertEquals(headerValue, callback.mTrailers.getAsMap().get("echo-header -name").get(0));
xunjieli 2016/01/27 16:16:38 I am not sure what "echo-header-name" came from, I
mef 2016/01/27 19:06:47 Done.
367 }
368
369 @SmallTest
370 @Feature({"Cronet"})
371 @OnlyRunNativeCronet
372 public void testCustomUserAgent() throws Exception {
373 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
374 String userAgentName = "User-Agent";
375 String userAgentValue = "User-Agent-Value";
376 BidirectionalStream.Builder builder =
377 new BidirectionalStream.Builder(Http2TestServer.getEchoHeaderUrl (userAgentName),
378 callback, callback.getExecutor(), mTestFramework.mCronet Engine);
379 builder.setHttpMethod("GET");
380 builder.addHeader(userAgentName, userAgentValue);
381 builder.build().start();
382 callback.blockForDone();
383 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
384 assertEquals(userAgentValue, callback.mResponseAsString);
385 }
386
387 @SmallTest
388 @Feature({"Cronet"})
389 @OnlyRunNativeCronet
390 public void testEchoStream() throws Exception {
xunjieli 2016/01/27 16:16:38 This test seems to be a combination of some other
mef 2016/01/27 19:06:47 This was THE original test of bidirectional stream
391 String url = Http2TestServer.getEchoStreamUrl();
392 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
393 String[] testData = {"Test String", makeLongString("1234567890", 50000), "woot!"};
394 StringBuilder stringData = new StringBuilder();
395 for (String writeData : testData) {
396 callback.addWriteData(writeData.getBytes());
397 stringData.append(writeData);
398 }
399 // Create stream.
400 BidirectionalStream stream =
401 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
402 mTestFramework.mCronetEngine)
403 .addHeader("foo", "Value with Spaces")
404 .addHeader("Content-Type", "zebra")
405 .build();
406 stream.start();
407 callback.blockForDone();
408 assertTrue(stream.isDone());
409 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
410 assertEquals(stringData.toString(), callback.mResponseAsString);
411 assertEquals(
412 "Value with Spaces", callback.mResponseInfo.getAllHeaders().get( "echo-foo").get(0));
413 assertEquals(
414 "zebra", callback.mResponseInfo.getAllHeaders().get("echo-conten t-type").get(0));
415 }
416
417 @SmallTest
418 @Feature({"Cronet"})
419 @OnlyRunNativeCronet
420 public void testEchoStreamEmptyWrite() throws Exception {
421 String url = Http2TestServer.getEchoStreamUrl();
422 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
423 callback.addWriteData(new byte[0]);
424 // Create stream.
425 BidirectionalStream stream =
426 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
427 mTestFramework.mCronetEngine)
428 .build();
429 stream.start();
430 callback.blockForDone();
431 assertTrue(stream.isDone());
432 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
433 assertEquals("", callback.mResponseAsString);
434 }
435
436 @SmallTest
437 @Feature({"Cronet"})
438 @OnlyRunNativeCronet
439 public void testDoubleWrite() throws Exception {
440 String url = Http2TestServer.getEchoStreamUrl();
441 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
442 callback.setAutoAdvance(false);
443 callback.addWriteData("1".getBytes());
444 callback.addWriteData("2".getBytes());
445 callback.addWriteData("3".getBytes());
446 // Create stream.
447 BidirectionalStream stream =
448 new BidirectionalStream.Builder(url, callback, callback.getBlock ingDirectExecutor(),
xunjieli 2016/01/26 21:41:10 I am not sure that executing the callbacks on the
mef 2016/01/27 19:06:47 Done. Initially I've used direct executor to preve
449 mTestFramework.mCronetEngine)
450 .build();
451 stream.start();
452 callback.waitForNextWriteStep();
453 // Executor will block the network thread posting the callback.
454 callback.closeDirectExecutorBlock();
455 // First write is allowed as there are no other writes in flight.
456 callback.startNextWrite(stream);
457 try {
458 // Second write may be allowed because onWriteCompleted callback is posted after state
xunjieli 2016/01/26 21:41:10 This doesn't seem very intuitive. We should be abl
mef 2016/01/27 19:06:47 Done.
459 // change.
460 callback.startNextWrite(stream);
461 // Third write must throw an exception, because executor is blocked in 'WRITING' state.
462 callback.startNextWrite(stream);
463 fail("Should throw an exception");
464 } catch (Exception e) {
465 assertEquals("Unexpected write attempt.", e.getMessage());
466 }
467
468 callback.setAutoAdvance(true);
469 // Open the executor. Stream should continue.
470 callback.openDirectExecutorBlock();
471 callback.blockForDone();
472 assertTrue(stream.isDone());
473 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
474 }
475
476 @SmallTest
477 @Feature({"Cronet"})
478 @OnlyRunNativeCronet
479 public void testDoubleRead() throws Exception {
480 String url = Http2TestServer.getEchoStreamUrl();
481 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
482 callback.setAutoAdvance(false);
483 String stringData = "12345";
484 callback.addWriteData(stringData.getBytes());
485 // Create stream.
486 BidirectionalStream stream =
487 new BidirectionalStream.Builder(url, callback, callback.getBlock ingDirectExecutor(),
488 mTestFramework.mCronetEngine)
489 .build();
490 stream.start();
491 callback.waitForNextReadStep();
492 callback.startNextWrite(stream);
493 callback.waitForNextWriteStep();
494 // Executor will block the network thread posting the callback.
495 callback.closeDirectExecutorBlock();
496 // Read next chunk of test data.
497 ByteBuffer readBuffer = ByteBuffer.allocateDirect(1);
498 // First read is allowed as there are no other read in flight.
499 callback.startNextRead(stream, readBuffer);
500 try {
501 // Second read may be allowed because onReadCompleted callback is po sted after state
502 // change.
503 callback.startNextRead(stream, readBuffer);
504 // Third read must throw an exception, becuase executor is blocked i n 'READING' state.
505 callback.startNextRead(stream, readBuffer);
506 fail("Should throw an exception");
507 } catch (Exception e) {
508 assertEquals("Unexpected read attempt.", e.getMessage());
509 }
510
511 callback.setAutoAdvance(true);
512 // Open the executor. Stream should continue.
513 callback.openDirectExecutorBlock();
514 callback.blockForDone();
515 assertTrue(stream.isDone());
516 assertEquals(stringData, callback.mResponseAsString);
517 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
518 }
519
520 @SmallTest
521 @Feature({"Cronet"})
522 @OnlyRunNativeCronet
523 public void testEchoStreamStepByStep() throws Exception {
524 String url = Http2TestServer.getEchoStreamUrl();
525 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
526 callback.setAutoAdvance(false);
527 String[] testData = {"a", "bb", "ccc", "Test String", "1234567890", "woo t!"};
528 StringBuilder stringData = new StringBuilder();
529 for (String writeData : testData) {
530 callback.addWriteData(writeData.getBytes());
531 stringData.append(writeData);
532 }
533 // Create stream.
534 BidirectionalStream stream =
535 new BidirectionalStream.Builder(url, callback, callback.getExecu tor(),
536 mTestFramework.mCronetEngine)
537 .build();
538 stream.start();
539 callback.waitForNextWriteStep();
540 callback.waitForNextReadStep();
541
542 for (String expected : testData) {
543 // Write next chunk of test data.
544 callback.startNextWrite(stream);
545 callback.waitForNextWriteStep();
546
547 // Read next chunk of test data.
548 ByteBuffer readBuffer = ByteBuffer.allocateDirect(100);
549 callback.startNextRead(stream, readBuffer);
550 callback.waitForNextReadStep();
551 assertEquals(expected.length(), readBuffer.position());
552 assertFalse(stream.isDone());
553 }
554
555 callback.setAutoAdvance(true);
556 callback.startNextRead(stream);
557 callback.blockForDone();
558 assertTrue(stream.isDone());
559 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
560 assertEquals(stringData.toString(), callback.mResponseAsString);
561 }
562
563 /**
564 * Checks that the buffer is updated correctly, when starting at an offset.
565 */
566 @SmallTest
567 @Feature({"Cronet"})
568 @OnlyRunNativeCronet
569 public void testSimpleGetBufferUpdates() throws Exception {
570 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
571 callback.setAutoAdvance(false);
572 // Since the method is "GET", the expected response body is also "GET".
573 BidirectionalStream.Builder builder =
574 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
575 callback.getExecutor(), mTestFramework.mCronetEngine);
576 BidirectionalStream stream = builder.setHttpMethod("GET").build();
577 stream.start();
578 callback.waitForNextReadStep();
579
580 assertEquals(null, callback.mError);
581 assertFalse(callback.isDone());
582 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED,
583 callback.mResponseStep);
584
585 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
586 readBuffer.put("FOR".getBytes());
587 assertEquals(3, readBuffer.position());
588
589 // Read first two characters of the response ("GE"). It's theoretically
590 // possible to need one read per character, though in practice,
591 // shouldn't happen.
592 while (callback.mResponseAsString.length() < 2) {
593 assertFalse(callback.isDone());
594 callback.startNextRead(stream, readBuffer);
595 callback.waitForNextReadStep();
596 }
597
598 // Make sure the two characters were read.
599 assertEquals("GE", callback.mResponseAsString);
600
601 // Check the contents of the entire buffer. The first 3 characters
602 // should not have been changed, and the last two should be the first
603 // two characters from the response.
604 assertEquals("FORGE", bufferContentsToString(readBuffer, 0, 5));
605 // The limit and position should be 5.
606 assertEquals(5, readBuffer.limit());
607 assertEquals(5, readBuffer.position());
608
609 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
610
611 // Start reading from position 3. Since the only remaining character
612 // from the response is a "T", when the read completes, the buffer
613 // should contain "FORTE", with a position() of 4 and a limit() of 5.
614 readBuffer.position(3);
615 callback.startNextRead(stream, readBuffer);
616 callback.waitForNextReadStep();
617
618 // Make sure all three characters of the response have now been read.
619 assertEquals("GET", callback.mResponseAsString);
620
621 // Check the entire contents of the buffer. Only the third character
622 // should have been modified.
623 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5));
624
625 // Make sure position and limit were updated correctly.
626 assertEquals(4, readBuffer.position());
627 assertEquals(5, readBuffer.limit());
628
629 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
630
631 // One more read attempt. The request should complete.
632 readBuffer.position(1);
633 readBuffer.limit(5);
634 callback.startNextRead(stream, readBuffer);
635 callback.waitForNextReadStep();
636
637 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
638 assertEquals("GET", callback.mResponseAsString);
639 checkResponseInfo(callback.mResponseInfo, Http2TestServer.getEchoMethodU rl(), 200, "");
640
641 // Check that buffer contents were not modified.
642 assertEquals("FORTE", bufferContentsToString(readBuffer, 0, 5));
643
644 // Position should not have been modified, since nothing was read.
645 assertEquals(1, readBuffer.position());
646 // Limit should be unchanged as always.
647 assertEquals(5, readBuffer.limit());
648
649 assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep);
650
651 // Make sure there are no other pending messages, which would trigger
652 // asserts in TestBidirectionalCallback.
653 testSimpleGet();
654 }
655
656 @SmallTest
657 @Feature({"Cronet"})
658 @OnlyRunNativeCronet
659 public void testBadBuffers() throws Exception {
660 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
661 callback.setAutoAdvance(false);
662 BidirectionalStream.Builder builder =
663 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
664 callback.getExecutor(), mTestFramework.mCronetEngine);
665 BidirectionalStream stream = builder.setHttpMethod("GET").build();
666 stream.start();
667 callback.waitForNextReadStep();
668
669 assertEquals(null, callback.mError);
670 assertFalse(callback.isDone());
671 assertEquals(TestBidirectionalStreamCallback.ResponseStep.ON_RESPONSE_ST ARTED,
672 callback.mResponseStep);
673
674 // Try to read using a full buffer.
675 try {
676 ByteBuffer readBuffer = ByteBuffer.allocateDirect(4);
677 readBuffer.put("full".getBytes());
678 stream.read(readBuffer);
679 fail("Exception not thrown");
680 } catch (IllegalArgumentException e) {
681 assertEquals("ByteBuffer is already full.", e.getMessage());
682 }
683
684 // Try to read using a non-direct buffer.
685 try {
686 ByteBuffer readBuffer = ByteBuffer.allocate(5);
687 stream.read(readBuffer);
688 fail("Exception not thrown");
689 } catch (Exception e) {
690 assertEquals("byteBuffer must be a direct ByteBuffer.", e.getMessage ());
691 }
692
693 // Finish the stream with a direct ByteBuffer.
694 callback.setAutoAdvance(true);
695 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
696 stream.read(readBuffer);
697 callback.blockForDone();
698 assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
699 assertEquals("GET", callback.mResponseAsString);
700 }
701
702 private void throwOrCancel(FailureType failureType, ResponseStep failureStep ,
703 boolean expectResponseInfo, boolean expectError) {
704 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
705 callback.setFailure(failureType, failureStep);
706 BidirectionalStream.Builder builder =
707 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
708 callback.getExecutor(), mTestFramework.mCronetEngine);
709 BidirectionalStream stream = builder.setHttpMethod("GET").build();
710 stream.start();
711 callback.blockForDone();
712 // assertEquals(callback.mResponseStep, failureStep);
713 assertTrue(stream.isDone());
714 assertEquals(expectResponseInfo, callback.mResponseInfo != null);
715 assertEquals(expectError, callback.mError != null);
716 assertEquals(expectError, callback.mOnErrorCalled);
717 assertEquals(failureType == FailureType.CANCEL_SYNC
718 || failureType == FailureType.CANCEL_ASYNC
719 || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE ,
720 callback.mOnCanceledCalled);
721 }
722
723 @SmallTest
724 @Feature({"Cronet"})
725 @OnlyRunNativeCronet
726 public void testFailures() throws Exception {
727 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_REQUEST_HEADERS_S ENT, false, false);
728 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_REQUEST_HEADERS_ SENT, false, false);
729 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE QUEST_HEADERS_SENT,
730 false, false);
731 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_REQUEST_HEADERS_SE NT, false, true);
732
733 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, false);
734 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_RESPONSE_STARTED , true, false);
735 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE SPONSE_STARTED,
736 true, false);
737 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED, true, true);
738
739 throwOrCancel(FailureType.CANCEL_SYNC, ResponseStep.ON_READ_COMPLETED, t rue, false);
740 throwOrCancel(FailureType.CANCEL_ASYNC, ResponseStep.ON_READ_COMPLETED, true, false);
741 throwOrCancel(FailureType.CANCEL_ASYNC_WITHOUT_PAUSE, ResponseStep.ON_RE AD_COMPLETED, true,
742 false);
743 throwOrCancel(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLETED, tr ue, true);
744 }
745
746 @SmallTest
747 @Feature({"Cronet"})
748 @OnlyRunNativeCronet
749 public void testThrowOnSucceeded() {
750 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
751 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_SUCCEEDED);
752 BidirectionalStream.Builder builder =
753 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
754 callback.getExecutor(), mTestFramework.mCronetEngine);
755 BidirectionalStream stream = builder.setHttpMethod("GET").build();
756 stream.start();
757 callback.blockForDone();
758 assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED);
759 assertTrue(stream.isDone());
760 assertNotNull(callback.mResponseInfo);
761 // Check that error thrown from 'onSucceeded' callback is not reported.
762 assertNull(callback.mError);
763 assertFalse(callback.mOnErrorCalled);
764 }
765
766 @SmallTest
767 @Feature({"Cronet"})
768 @OnlyRunNativeCronet
769 public void testExecutorShutdownBeforeStreamIsDone() {
770 // Test that stream is destroyed even if executor is shutdown and reject s posting tasks.
xunjieli 2016/01/27 16:16:38 nit: s/shutdown/shut down
mef 2016/01/27 19:06:47 Done.
771 TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCa llback();
772 callback.setAutoAdvance(false);
773 BidirectionalStream.Builder builder =
774 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
775 callback.getExecutor(), mTestFramework.mCronetEngine);
776 CronetBidirectionalStream stream =
777 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
778 stream.start();
779 callback.waitForNextReadStep();
780 assertFalse(callback.isDone());
781 assertFalse(stream.isDone());
782
783 final ConditionVariable streamDestroyed = new ConditionVariable(false);
784 stream.setOnDestroyedCallbackForTesting(new Runnable() {
785 @Override
786 public void run() {
787 streamDestroyed.open();
788 }
789 });
790
791 // Shut down the executor, so posting the task will throw an exception.
792 callback.shutdownExecutor();
793 ByteBuffer readBuffer = ByteBuffer.allocateDirect(5);
794 stream.read(readBuffer);
795 // Callback will never be called again because executor is shut down,
796 // but stream will be destroyed from network thread.
797 streamDestroyed.block();
798
799 assertFalse(callback.isDone());
800 assertTrue(stream.isDone());
801 }
802
803 /**
804 * Callback that shuts down the engine when the stream has succeeded
805 * or failed.
806 */
807 private class ShutdownTestBidirectionalStreamCallback extends TestBidirectio nalStreamCallback {
808 @Override
809 public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info ) {
810 mTestFramework.mCronetEngine.shutdown();
811 // Clear mCronetEngine so it doesn't get shut down second time in te arDown().
812 mTestFramework.mCronetEngine = null;
813 super.onSucceeded(stream, info);
814 }
815
816 @Override
817 public void onFailed(
818 BidirectionalStream stream, UrlResponseInfo info, CronetExceptio n error) {
819 mTestFramework.mCronetEngine.shutdown();
820 // Clear mCronetEngine so it doesn't get shut down second time in te arDown().
821 mTestFramework.mCronetEngine = null;
822 super.onFailed(stream, info, error);
823 }
824
825 @Override
826 public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {
827 mTestFramework.mCronetEngine.shutdown();
828 // Clear mCronetEngine so it doesn't get shut down second time in te arDown().
829 mTestFramework.mCronetEngine = null;
830 super.onCanceled(stream, info);
831 }
832 }
833
834 @SmallTest
835 @Feature({"Cronet"})
836 @OnlyRunNativeCronet
837 public void testCronetEngineShutdown() throws Exception {
838 // Test that CronetEngine cannot be shut down if there are any active st reams.
839 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
840 // Block callback when response starts to verify that shutdown fails
841 // if there are active streams.
842 callback.setAutoAdvance(false);
843 BidirectionalStream.Builder builder =
844 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
845 callback.getExecutor(), mTestFramework.mCronetEngine);
846 CronetBidirectionalStream stream =
847 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
848 stream.start();
849 try {
850 mTestFramework.mCronetEngine.shutdown();
851 fail("Should throw an exception");
852 } catch (Exception e) {
853 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
xunjieli 2016/01/27 16:16:38 nit: s/shutdown/shut down, or "Cannot call shutdow
mef 2016/01/27 19:06:47 That's the exception message, untouched by this C
854 }
855
856 callback.waitForNextReadStep();
857 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
858 try {
859 mTestFramework.mCronetEngine.shutdown();
860 fail("Should throw an exception");
861 } catch (Exception e) {
862 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
863 }
864 callback.startNextRead(stream);
865
866 callback.waitForNextReadStep();
867 assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
868 try {
869 mTestFramework.mCronetEngine.shutdown();
870 fail("Should throw an exception");
871 } catch (Exception e) {
872 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
873 }
874
875 // May not have read all the data, in theory. Just enable auto-advance
876 // and finish the request.
877 callback.setAutoAdvance(true);
878 callback.startNextRead(stream);
879 callback.blockForDone();
880 }
881
882 @SmallTest
883 @Feature({"Cronet"})
884 @OnlyRunNativeCronet
885 public void testCronetEngineShutdownAfterStreamFailure() throws Exception {
886 // Test that CronetEngine can be shut down after stream reports a failur e.
887 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
888 BidirectionalStream.Builder builder =
889 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
890 callback.getExecutor(), mTestFramework.mCronetEngine);
891 CronetBidirectionalStream stream =
892 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
893 stream.start();
894 callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_READ_COMPLET ED);
895 callback.blockForDone();
896 assertTrue(callback.mOnErrorCalled);
897 }
898
899 @SmallTest
900 @Feature({"Cronet"})
901 @OnlyRunNativeCronet
902 public void testCronetEngineShutdownAfterStreamCancel() throws Exception {
903 // Test that CronetEngine can be shut down after stream is canceled.
904 TestBidirectionalStreamCallback callback = new ShutdownTestBidirectional StreamCallback();
905 BidirectionalStream.Builder builder =
906 new BidirectionalStream.Builder(Http2TestServer.getEchoMethodUrl (), callback,
907 callback.getExecutor(), mTestFramework.mCronetEngine);
908 CronetBidirectionalStream stream =
909 (CronetBidirectionalStream) builder.setHttpMethod("GET").build() ;
910
911 // Block callback when response starts to verify that shutdown fails
912 // if there are active requests.
913 callback.setAutoAdvance(false);
914 stream.start();
915 try {
916 mTestFramework.mCronetEngine.shutdown();
917 fail("Should throw an exception");
918 } catch (Exception e) {
919 assertEquals("Cannot shutdown with active requests.", e.getMessage() );
920 }
921 callback.waitForNextReadStep();
922 assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
923 stream.cancel();
xunjieli 2016/01/27 16:16:38 testCronetEngineShutdownAfterStreamFailure and tes
mef 2016/01/27 19:06:47 Done.
924 }
925
926 // Returns the contents of byteBuffer, from its position() to its limit(),
927 // as a String. Does not modify byteBuffer's position().
928 private static String bufferContentsToString(ByteBuffer byteBuffer, int star t, int end) {
929 // Use a duplicate to avoid modifying byteBuffer.
930 ByteBuffer duplicate = byteBuffer.duplicate();
931 duplicate.position(start);
932 duplicate.limit(end);
933 byte[] contents = new byte[duplicate.remaining()];
934 duplicate.get(contents);
935 return new String(contents);
120 } 936 }
121 } 937 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698