Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.net; | 5 package org.chromium.net; |
| 6 | 6 |
| 7 import android.os.ConditionVariable; | |
| 7 import android.test.suitebuilder.annotation.SmallTest; | 8 import android.test.suitebuilder.annotation.SmallTest; |
| 8 | 9 |
| 9 import org.chromium.base.test.util.Feature; | 10 import org.chromium.base.test.util.Feature; |
| 11 import org.chromium.net.CronetTestBase.OnlyRunNativeCronet; | |
| 12 import org.chromium.net.TestBidirectionalStreamCallback.FailureType; | |
| 13 import org.chromium.net.TestBidirectionalStreamCallback.ResponseStep; | |
| 10 | 14 |
| 11 import java.nio.ByteBuffer; | 15 import java.nio.ByteBuffer; |
| 12 import java.util.concurrent.Executor; | 16 import java.util.AbstractMap; |
| 13 import java.util.concurrent.ExecutorService; | 17 import java.util.ArrayList; |
| 14 import java.util.concurrent.Executors; | 18 import java.util.Arrays; |
| 15 import java.util.concurrent.ThreadFactory; | 19 import java.util.List; |
| 20 import java.util.Map; | |
| 21 import java.util.regex.Matcher; | |
| 22 import java.util.regex.Pattern; | |
| 16 | 23 |
| 17 /** | 24 /** |
| 18 * Test functionality of BidirectionalStream interface. | 25 * Test functionality of BidirectionalStream interface. |
| 19 */ | 26 */ |
| 20 public class BidirectionalStreamTest extends CronetTestBase { | 27 public class BidirectionalStreamTest extends CronetTestBase { |
| 21 private CronetTestFramework mTestFramework; | 28 private CronetTestFramework mTestFramework; |
| 22 | 29 |
| 23 @Override | 30 @Override |
| 24 protected void setUp() throws Exception { | 31 protected void setUp() throws Exception { |
| 25 super.setUp(); | 32 super.setUp(); |
| 26 mTestFramework = startCronetTestFramework(); | 33 // Load library first to create MockCertVerifier. |
| 27 assertTrue(NativeTestServer.startNativeTestServer(getContext())); | 34 System.loadLibrary("cronet_tests"); |
| 28 // Add url interceptors after native application context is initialized. | 35 CronetEngine.Builder builder = new CronetEngine.Builder(getContext()); |
| 29 MockUrlRequestJobFactory.setUp(); | 36 builder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerif ier()); |
| 37 | |
| 38 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n ull, builder); | |
| 39 assertTrue(Http2TestServer.startHttp2TestServer( | |
| 40 getContext(), QuicTestServer.getServerCert(), QuicTestServer.get ServerCertKey())); | |
| 30 } | 41 } |
| 31 | 42 |
| 32 @Override | 43 @Override |
| 33 protected void tearDown() throws Exception { | 44 protected void tearDown() throws Exception { |
| 34 NativeTestServer.shutdownNativeTestServer(); | 45 assertTrue(Http2TestServer.shutdownHttp2TestServer()); |
| 35 mTestFramework.mCronetEngine.shutdown(); | 46 if (mTestFramework.mCronetEngine != null) { |
| 47 mTestFramework.mCronetEngine.shutdown(); | |
| 48 } | |
| 36 super.tearDown(); | 49 super.tearDown(); |
| 37 } | 50 } |
| 38 | 51 |
| 39 private class TestBidirectionalStreamCallback extends BidirectionalStream.Ca llback { | 52 private TestBidirectionalStreamCallback startAndWaitForComplete(String url) throws Exception { |
|
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 } |
| OLD | NEW |