1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net.impl; 6 7 import static android.os.Process.THREAD_PRIORITY_BACKGROUND; 8 import static android.os.Process.THREAD_PRIORITY_DEFAULT; 9 10 import static org.junit.Assert.assertEquals; 11 import static org.junit.Assert.assertFalse; 12 import static org.junit.Assert.assertNotEquals; 13 import static org.junit.Assert.assertNotNull; 14 import static org.junit.Assert.assertTrue; 15 16 import static android.net.http.HttpEngine.Builder.HTTP_CACHE_DISK_NO_HTTP; 17 18 import android.content.Context; 19 import android.net.http.HeaderBlock; 20 import android.net.http.HttpEngine; 21 import android.os.Build; 22 import android.os.ConditionVariable; 23 24 import androidx.test.filters.SmallTest; 25 26 import org.json.JSONException; 27 import org.json.JSONObject; 28 import org.junit.After; 29 import org.junit.Before; 30 import org.junit.Rule; 31 import org.junit.Test; 32 import org.junit.rules.RuleChain; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 36 import org.chromium.net.CronetLoggerTestRule; 37 import org.chromium.net.CronetTestRule; 38 import org.chromium.net.CronetTestRule.CronetTestFramework; 39 import org.chromium.net.CronetTestRule.OnlyRunNativeCronet; 40 import org.chromium.net.CronetTestRule.RequiresMinAndroidApi; 41 import android.net.http.ExperimentalHttpEngine; 42 import org.chromium.net.NativeTestServer; 43 import org.chromium.net.TestUrlRequestCallback; 44 import android.net.http.UrlRequest; 45 import org.chromium.net.impl.CronetEngineBuilderImpl.HttpCacheMode; 46 import org.chromium.net.impl.CronetLogger.CronetEngineBuilderInfo; 47 import org.chromium.net.impl.CronetLogger.CronetSource; 48 import org.chromium.net.impl.CronetLogger.CronetTrafficInfo; 49 import org.chromium.net.impl.CronetLogger.CronetVersion; 50 51 import java.time.Duration; 52 import java.util.AbstractMap; 53 import java.util.Arrays; 54 import java.util.Collections; 55 import java.util.HashMap; 56 import java.util.List; 57 import java.util.Locale; 58 import java.util.Map; 59 import java.util.concurrent.atomic.AtomicInteger; 60 import java.util.concurrent.atomic.AtomicReference; 61 62 /** 63 * Test logging functionalities. 64 */ 65 @RunWith(JUnit4.class) 66 @RequiresMinAndroidApi(Build.VERSION_CODES.O) 67 public final class CronetLoggerTest { 68 private final CronetTestRule mTestRule = new CronetTestRule(); 69 private final CronetLoggerTestRule mLoggerTestRule = new CronetLoggerTestRule(new TestLogger()); 70 71 @Rule 72 public final RuleChain chain = RuleChain.outerRule(mTestRule).around(mLoggerTestRule); 73 74 private TestLogger mTestLogger; 75 private Context mContext; 76 private CronetTestFramework mTestFramework; 77 78 /** 79 * Records the last engine creation (and traffic info) call it has received. 80 */ 81 public static final class TestLogger extends CronetLogger { 82 private AtomicInteger mCallsToLogCronetEngineCreation = new AtomicInteger(); 83 private AtomicInteger mCallsToLogCronetTrafficInfo = new AtomicInteger(); 84 private AtomicInteger mCronetEngineId = new AtomicInteger(); 85 private AtomicInteger mCronetRequestId = new AtomicInteger(); 86 private AtomicReference<CronetTrafficInfo> mTrafficInfo = new AtomicReference<>(); 87 private AtomicReference<CronetEngineBuilderInfo> mBuilderInfo = new AtomicReference<>(); 88 private AtomicReference<CronetVersion> mVersion = new AtomicReference<>(); 89 private AtomicReference<CronetSource> mSource = new AtomicReference<>(); 90 private final ConditionVariable mBlock = new ConditionVariable(); 91 92 @Override logCronetEngineCreation(int cronetEngineId, CronetEngineBuilderInfo engineBuilderInfo, CronetVersion version, CronetSource source)93 public void logCronetEngineCreation(int cronetEngineId, 94 CronetEngineBuilderInfo engineBuilderInfo, CronetVersion version, 95 CronetSource source) { 96 mCallsToLogCronetEngineCreation.incrementAndGet(); 97 mCronetEngineId.set(cronetEngineId); 98 mBuilderInfo.set(engineBuilderInfo); 99 mVersion.set(version); 100 mSource.set(source); 101 } 102 103 @Override logCronetTrafficInfo(int cronetEngineId, CronetTrafficInfo trafficInfo)104 public void logCronetTrafficInfo(int cronetEngineId, CronetTrafficInfo trafficInfo) { 105 mCallsToLogCronetTrafficInfo.incrementAndGet(); 106 mCronetRequestId.set(cronetEngineId); 107 mTrafficInfo.set(trafficInfo); 108 mBlock.open(); 109 } 110 callsToLogCronetTrafficInfo()111 public int callsToLogCronetTrafficInfo() { 112 return mCallsToLogCronetTrafficInfo.get(); 113 } 114 callsToLogCronetEngineCreation()115 public int callsToLogCronetEngineCreation() { 116 return mCallsToLogCronetEngineCreation.get(); 117 } 118 waitForLogCronetTrafficInfo()119 public void waitForLogCronetTrafficInfo() { 120 mBlock.block(); 121 mBlock.close(); 122 } 123 getLastCronetEngineId()124 public int getLastCronetEngineId() { 125 return mCronetEngineId.get(); 126 } 127 getLastCronetRequestId()128 public int getLastCronetRequestId() { 129 return mCronetRequestId.get(); 130 } 131 getLastCronetTrafficInfo()132 public CronetTrafficInfo getLastCronetTrafficInfo() { 133 return mTrafficInfo.get(); 134 } 135 getLastCronetEngineBuilderInfo()136 public CronetEngineBuilderInfo getLastCronetEngineBuilderInfo() { 137 return mBuilderInfo.get(); 138 } 139 getLastCronetVersion()140 public CronetVersion getLastCronetVersion() { 141 return mVersion.get(); 142 } 143 getLastCronetSource()144 public CronetSource getLastCronetSource() { 145 return mSource.get(); 146 } 147 } 148 149 @Before setUp()150 public void setUp() { 151 mContext = CronetTestRule.getContext(); 152 mTestFramework = mTestRule.buildCronetTestFramework(); 153 mTestLogger = (TestLogger) mLoggerTestRule.mTestLogger; 154 assertTrue(NativeTestServer.startNativeTestServer(mContext)); 155 } 156 157 @After tearDown()158 public void tearDown() { 159 mTestLogger = null; 160 NativeTestServer.shutdownNativeTestServer(); 161 mTestFramework.shutdownEngine(); 162 } 163 164 @Test 165 @SmallTest testCronetEngineInfoCreation()166 public void testCronetEngineInfoCreation() { 167 CronetEngineBuilderImpl builder = new NativeCronetEngineBuilderImpl(mContext); 168 CronetEngineBuilderInfo builderInfo = new CronetEngineBuilderInfo(builder); 169 assertEquals(builder.publicKeyPinningBypassForLocalTrustAnchorsEnabled(), 170 builderInfo.isPublicKeyPinningBypassForLocalTrustAnchorsEnabled()); 171 assertEquals(builder.getUserAgent(), builderInfo.getUserAgent()); 172 assertEquals(builder.storagePath(), builderInfo.getStoragePath()); 173 assertEquals(builder.quicEnabled(), builderInfo.isQuicEnabled()); 174 assertEquals(builder.http2Enabled(), builderInfo.isHttp2Enabled()); 175 assertEquals(builder.brotliEnabled(), builderInfo.isBrotliEnabled()); 176 assertEquals(builder.httpCacheMode(), builderInfo.getHttpCacheMode()); 177 assertEquals(builder.experimentalOptions(), builderInfo.getExperimentalOptions()); 178 assertEquals(builder.networkQualityEstimatorEnabled(), 179 builderInfo.isNetworkQualityEstimatorEnabled()); 180 assertEquals(builder.threadPriority(THREAD_PRIORITY_BACKGROUND), 181 builderInfo.getThreadPriority()); 182 } 183 184 @Test 185 @SmallTest testCronetVersionCreation()186 public void testCronetVersionCreation() { 187 final int major = 100; 188 final int minor = 0; 189 final int build = 1; 190 final int patch = 33; 191 final String version = String.format(Locale.US, "%d.%d.%d.%d", major, minor, build, patch); 192 final CronetVersion parsedVersion = new CronetVersion(version); 193 assertEquals(major, parsedVersion.getMajorVersion()); 194 assertEquals(minor, parsedVersion.getMinorVersion()); 195 assertEquals(build, parsedVersion.getBuildVersion()); 196 assertEquals(patch, parsedVersion.getPatchVersion()); 197 } 198 199 @Test 200 @SmallTest testHttpCacheModeEnum()201 public void testHttpCacheModeEnum() { 202 final int publicBuilderHttpCacheModes[] = {HttpEngine.Builder.HTTP_CACHE_DISABLED, 203 HttpEngine.Builder.HTTP_CACHE_IN_MEMORY, 204 HttpEngine.Builder.HTTP_CACHE_DISK_NO_HTTP, HttpEngine.Builder.HTTP_CACHE_DISK}; 205 for (int publicBuilderHttpCacheMode : publicBuilderHttpCacheModes) { 206 HttpCacheMode cacheModeEnum = 207 HttpCacheMode.fromPublicBuilderCacheMode(publicBuilderHttpCacheMode); 208 assertEquals(publicBuilderHttpCacheMode, cacheModeEnum.toPublicBuilderCacheMode()); 209 } 210 } 211 212 @Test 213 @SmallTest testSetLoggerForTesting()214 public void testSetLoggerForTesting() { 215 CronetLogger logger = CronetLoggerFactory.createLogger(mContext, null); 216 assertEquals(0, mTestLogger.callsToLogCronetTrafficInfo()); 217 assertEquals(0, mTestLogger.callsToLogCronetEngineCreation()); 218 219 // We don't care about what's being logged. 220 logger.logCronetTrafficInfo(0, null); 221 assertEquals(1, mTestLogger.callsToLogCronetTrafficInfo()); 222 assertEquals(0, mTestLogger.callsToLogCronetEngineCreation()); 223 logger.logCronetEngineCreation(0, null, null, null); 224 assertEquals(1, mTestLogger.callsToLogCronetTrafficInfo()); 225 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 226 } 227 228 @Test 229 @SmallTest 230 @OnlyRunNativeCronet testTelemetryDefaultDisabled()231 public void testTelemetryDefaultDisabled() throws JSONException { 232 final String url = NativeTestServer.getEchoBodyURL(); 233 234 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 235 HttpEngine engine = mTestFramework.startEngine(); 236 UrlRequest.Builder requestBuilder = 237 engine.newUrlRequestBuilder(url, callback, callback.getExecutor()); 238 UrlRequest request = requestBuilder.build(); 239 request.start(); 240 callback.blockForDone(); 241 242 // Test-logger should be bypassed. 243 assertEquals(0, mTestLogger.callsToLogCronetEngineCreation()); 244 assertEquals(0, mTestLogger.callsToLogCronetTrafficInfo()); 245 } 246 247 @Test 248 @SmallTest 249 @OnlyRunNativeCronet testEngineCreation()250 public void testEngineCreation() throws JSONException { 251 JSONObject staleDns = new JSONObject() 252 .put("enable", true) 253 .put("delay_ms", 0) 254 .put("allow_other_network", true) 255 .put("persist_to_disk", true) 256 .put("persist_delay_ms", 0); 257 final JSONObject jsonExperimentalOptions = 258 new JSONObject().put("StaleDNS", staleDns).put("enable_telemetry", true); 259 final String experimentalOptions = jsonExperimentalOptions.toString(); 260 final boolean isPublicKeyPinningBypassForLocalTrustAnchorsEnabled = false; 261 final String userAgent = "myUserAgent"; 262 final String storagePath = CronetTestRule.getTestStorage(mContext); 263 final boolean isQuicEnabled = true; 264 final boolean isHttp2Enabled = false; 265 final boolean isBrotliEnabled = true; 266 final int cacheMode = HTTP_CACHE_DISK_NO_HTTP; 267 final boolean isNetworkQualityEstimatorEnabled = true; 268 final int threadPriority = THREAD_PRIORITY_DEFAULT; 269 270 ExperimentalHttpEngine.Builder builder = 271 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 272 273 builder.setExperimentalOptions(experimentalOptions); 274 builder.setEnablePublicKeyPinningBypassForLocalTrustAnchors( 275 isPublicKeyPinningBypassForLocalTrustAnchorsEnabled); 276 builder.setUserAgent(userAgent); 277 builder.setStoragePath(storagePath); 278 builder.setEnableQuic(isQuicEnabled); 279 builder.setEnableHttp2(isHttp2Enabled); 280 builder.setEnableBrotli(isBrotliEnabled); 281 builder.setEnableHttpCache(cacheMode, 0); 282 283 builder.enableNetworkQualityEstimator(isNetworkQualityEstimatorEnabled); 284 builder.setThreadPriority(threadPriority); 285 286 mTestFramework.startEngine(); 287 final CronetEngineBuilderInfo builderInfo = mTestLogger.getLastCronetEngineBuilderInfo(); 288 final CronetVersion version = mTestLogger.getLastCronetVersion(); 289 final CronetSource source = mTestLogger.getLastCronetSource(); 290 291 assertEquals(isPublicKeyPinningBypassForLocalTrustAnchorsEnabled, 292 builderInfo.isPublicKeyPinningBypassForLocalTrustAnchorsEnabled()); 293 assertEquals(userAgent, builderInfo.getUserAgent()); 294 assertEquals(storagePath, builderInfo.getStoragePath()); 295 assertEquals(isQuicEnabled, builderInfo.isQuicEnabled()); 296 assertEquals(isHttp2Enabled, builderInfo.isHttp2Enabled()); 297 assertEquals(isBrotliEnabled, builderInfo.isBrotliEnabled()); 298 assertEquals(cacheMode, builderInfo.getHttpCacheMode()); 299 assertEquals(experimentalOptions, builderInfo.getExperimentalOptions()); 300 assertEquals( 301 isNetworkQualityEstimatorEnabled, builderInfo.isNetworkQualityEstimatorEnabled()); 302 assertEquals(threadPriority, builderInfo.getThreadPriority()); 303 assertEquals(ImplVersion.getCronetVersion(), version.toString()); 304 if (mTestRule.testingJavaImpl()) { 305 assertEquals(CronetSource.CRONET_SOURCE_FALLBACK, source); 306 } else { 307 assertEquals(CronetSource.CRONET_SOURCE_STATICALLY_LINKED, source); 308 } 309 310 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 311 assertEquals(0, mTestLogger.callsToLogCronetTrafficInfo()); 312 } 313 314 @Test 315 @SmallTest 316 @OnlyRunNativeCronet testEngineCreationAndTrafficInfoEngineId()317 public void testEngineCreationAndTrafficInfoEngineId() throws Exception { 318 JSONObject jsonExperimentalOptions = new JSONObject().put("enable_telemetry", true); 319 final String experimentalOptions = jsonExperimentalOptions.toString(); 320 final String url = "www.example.com"; 321 ExperimentalHttpEngine.Builder builder = 322 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 323 builder.setExperimentalOptions(experimentalOptions); 324 HttpEngine engine = mTestFramework.startEngine(); 325 final int engineId = mTestLogger.getLastCronetEngineId(); 326 327 TestUrlRequestCallback callback1 = new TestUrlRequestCallback(); 328 UrlRequest.Builder requestBuilder1 = 329 engine.newUrlRequestBuilder(url, callback1, callback1.getExecutor()); 330 UrlRequest request1 = requestBuilder1.build(); 331 TestUrlRequestCallback callback2 = new TestUrlRequestCallback(); 332 UrlRequest.Builder requestBuilder2 = 333 engine.newUrlRequestBuilder(url, callback2, callback2.getExecutor()); 334 UrlRequest request2 = requestBuilder2.build(); 335 336 request1.start(); 337 callback1.blockForDone(); 338 mTestLogger.waitForLogCronetTrafficInfo(); 339 final int request1Id = mTestLogger.getLastCronetRequestId(); 340 341 request2.start(); 342 callback2.blockForDone(); 343 mTestLogger.waitForLogCronetTrafficInfo(); 344 final int request2Id = mTestLogger.getLastCronetRequestId(); 345 346 assertEquals(engineId, request1Id); 347 assertEquals(engineId, request2Id); 348 349 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 350 assertEquals(2, mTestLogger.callsToLogCronetTrafficInfo()); 351 } 352 353 @Test 354 @SmallTest 355 @OnlyRunNativeCronet testMultipleEngineCreationAndTrafficInfoEngineId()356 public void testMultipleEngineCreationAndTrafficInfoEngineId() throws Exception { 357 JSONObject jsonExperimentalOptions = new JSONObject().put("enable_telemetry", true); 358 final String experimentalOptions = jsonExperimentalOptions.toString(); 359 final String url = "www.example.com"; 360 ExperimentalHttpEngine.Builder engineBuilder = 361 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 362 engineBuilder.setExperimentalOptions(experimentalOptions); 363 364 HttpEngine engine1 = engineBuilder.build(); 365 final int engine1Id = mTestLogger.getLastCronetEngineId(); 366 HttpEngine engine2 = engineBuilder.build(); 367 final int engine2Id = mTestLogger.getLastCronetEngineId(); 368 369 TestUrlRequestCallback callback1 = new TestUrlRequestCallback(); 370 UrlRequest.Builder requestBuilder1 = 371 engine1.newUrlRequestBuilder(url, callback1, callback1.getExecutor()); 372 UrlRequest request1 = requestBuilder1.build(); 373 TestUrlRequestCallback callback2 = new TestUrlRequestCallback(); 374 UrlRequest.Builder requestBuilder2 = 375 engine2.newUrlRequestBuilder(url, callback2, callback2.getExecutor()); 376 UrlRequest request2 = requestBuilder2.build(); 377 378 request1.start(); 379 callback1.blockForDone(); 380 mTestLogger.waitForLogCronetTrafficInfo(); 381 final int request1Id = mTestLogger.getLastCronetRequestId(); 382 383 request2.start(); 384 callback2.blockForDone(); 385 mTestLogger.waitForLogCronetTrafficInfo(); 386 final int request2Id = mTestLogger.getLastCronetRequestId(); 387 388 assertEquals(engine1Id, request1Id); 389 assertEquals(engine2Id, request2Id); 390 391 assertEquals(2, mTestLogger.callsToLogCronetEngineCreation()); 392 assertEquals(2, mTestLogger.callsToLogCronetTrafficInfo()); 393 394 engine1.shutdown(); 395 engine2.shutdown(); 396 } 397 398 @Test 399 @SmallTest 400 @OnlyRunNativeCronet testSuccessfulRequestNative()401 public void testSuccessfulRequestNative() throws Exception { 402 JSONObject jsonExperimentalOptions = new JSONObject().put("enable_telemetry", true); 403 final String experimentalOptions = jsonExperimentalOptions.toString(); 404 final String url = NativeTestServer.getEchoBodyURL(); 405 ExperimentalHttpEngine.Builder engineBuilder = 406 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 407 engineBuilder.setExperimentalOptions(experimentalOptions); 408 HttpEngine engine = mTestFramework.startEngine(); 409 410 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 411 UrlRequest.Builder requestBuilder = 412 engine.newUrlRequestBuilder(url, callback, callback.getExecutor()); 413 UrlRequest request = requestBuilder.build(); 414 request.start(); 415 callback.blockForDone(); 416 assertFalse(callback.mOnCanceledCalled); 417 assertFalse(callback.mOnErrorCalled); 418 mTestLogger.waitForLogCronetTrafficInfo(); 419 420 final CronetTrafficInfo trafficInfo = mTestLogger.getLastCronetTrafficInfo(); 421 assertEquals(0, trafficInfo.getRequestHeaderSizeInBytes()); 422 assertNotEquals(0, trafficInfo.getRequestBodySizeInBytes()); 423 assertNotEquals(0, trafficInfo.getResponseHeaderSizeInBytes()); 424 assertNotEquals(0, trafficInfo.getResponseBodySizeInBytes()); 425 assertEquals(200, trafficInfo.getResponseStatusCode()); 426 assertNotEquals(Duration.ofSeconds(0), trafficInfo.getHeadersLatency()); 427 assertNotEquals(Duration.ofSeconds(0), trafficInfo.getTotalLatency()); 428 assertNotNull(trafficInfo.getNegotiatedProtocol()); 429 assertFalse(trafficInfo.wasConnectionMigrationAttempted()); 430 assertFalse(trafficInfo.didConnectionMigrationSucceed()); 431 432 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 433 assertEquals(1, mTestLogger.callsToLogCronetTrafficInfo()); 434 } 435 436 @Test 437 @SmallTest 438 @OnlyRunNativeCronet testFailedRequestNative()439 public void testFailedRequestNative() throws Exception { 440 JSONObject jsonExperimentalOptions = new JSONObject().put("enable_telemetry", true); 441 final String url = "www.unreachable-url.com"; 442 final String experimentalOptions = jsonExperimentalOptions.toString(); 443 ExperimentalHttpEngine.Builder engineBuilder = 444 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 445 engineBuilder.setExperimentalOptions(experimentalOptions); 446 HttpEngine engine = mTestFramework.startEngine(); 447 448 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 449 UrlRequest.Builder requestBuilder = 450 engine.newUrlRequestBuilder(url, callback, callback.getExecutor()); 451 UrlRequest request = requestBuilder.build(); 452 request.start(); 453 callback.blockForDone(); 454 assertFalse(callback.mOnCanceledCalled); 455 assertTrue(callback.mOnErrorCalled); 456 mTestLogger.waitForLogCronetTrafficInfo(); 457 458 final CronetTrafficInfo trafficInfo = mTestLogger.getLastCronetTrafficInfo(); 459 assertEquals(0, trafficInfo.getRequestHeaderSizeInBytes()); 460 assertEquals(0, trafficInfo.getRequestBodySizeInBytes()); 461 assertEquals(0, trafficInfo.getResponseHeaderSizeInBytes()); 462 assertEquals(0, trafficInfo.getResponseBodySizeInBytes()); 463 // When a request fails before hitting the server all these values won't be populated in 464 // the actual code. Check that the logger sets them to some known defaults before 465 // logging. 466 assertEquals(0, trafficInfo.getResponseStatusCode()); 467 assertEquals("", trafficInfo.getNegotiatedProtocol()); 468 assertFalse(trafficInfo.wasConnectionMigrationAttempted()); 469 assertFalse(trafficInfo.didConnectionMigrationSucceed()); 470 471 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 472 assertEquals(1, mTestLogger.callsToLogCronetTrafficInfo()); 473 } 474 475 @Test 476 @SmallTest 477 @OnlyRunNativeCronet testCanceledRequestNative()478 public void testCanceledRequestNative() throws Exception { 479 JSONObject jsonExperimentalOptions = new JSONObject().put("enable_telemetry", true); 480 final String experimentalOptions = jsonExperimentalOptions.toString(); 481 final String url = NativeTestServer.getEchoBodyURL(); 482 ExperimentalHttpEngine.Builder engineBuilder = 483 (ExperimentalHttpEngine.Builder) mTestFramework.mBuilder; 484 engineBuilder.setExperimentalOptions(experimentalOptions); 485 HttpEngine engine = mTestFramework.startEngine(); 486 487 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 488 callback.setAutoAdvance(false); 489 UrlRequest.Builder requestBuilder = 490 engine.newUrlRequestBuilder(url, callback, callback.getExecutor()); 491 UrlRequest request = requestBuilder.build(); 492 request.start(); 493 request.cancel(); 494 callback.blockForDone(); 495 assertTrue(callback.mOnCanceledCalled); 496 assertFalse(callback.mOnErrorCalled); 497 mTestLogger.waitForLogCronetTrafficInfo(); 498 499 final CronetTrafficInfo trafficInfo = mTestLogger.getLastCronetTrafficInfo(); 500 assertEquals(0, trafficInfo.getRequestHeaderSizeInBytes()); 501 assertEquals(0, trafficInfo.getRequestBodySizeInBytes()); 502 assertEquals(0, trafficInfo.getResponseHeaderSizeInBytes()); 503 assertEquals(0, trafficInfo.getResponseBodySizeInBytes()); 504 // When a request fails before hitting the server all these values won't be populated in 505 // the actual code. Check that the logger sets them to some known defaults before 506 // logging. 507 assertEquals(0, trafficInfo.getResponseStatusCode()); 508 assertEquals("", trafficInfo.getNegotiatedProtocol()); 509 assertFalse(trafficInfo.wasConnectionMigrationAttempted()); 510 assertFalse(trafficInfo.didConnectionMigrationSucceed()); 511 512 assertEquals(1, mTestLogger.callsToLogCronetEngineCreation()); 513 assertEquals(1, mTestLogger.callsToLogCronetTrafficInfo()); 514 } 515 516 @Test 517 @SmallTest 518 @OnlyRunNativeCronet testEmptyHeadersSizeNative()519 public void testEmptyHeadersSizeNative() { 520 Map<String, List<String>> headers = Collections.emptyMap(); 521 assertEquals(0, CronetUrlRequest.estimateHeadersSizeInBytes(headers)); 522 headers = null; 523 assertEquals(0, CronetUrlRequest.estimateHeadersSizeInBytes(headers)); 524 525 HeaderBlock headerBlock = asHeaderBlock(new CronetUrlRequest.HeadersList()); 526 assertEquals(0, CronetUrlRequest.estimateHeadersSizeInBytes(headerBlock)); 527 headerBlock = null; 528 assertEquals(0, CronetUrlRequest.estimateHeadersSizeInBytes(headerBlock)); 529 } 530 531 @Test 532 @SmallTest 533 @OnlyRunNativeCronet testNonEmptyHeadersSizeNative()534 public void testNonEmptyHeadersSizeNative() { 535 Map<String, List<String>> headers = new HashMap<String, List<String>>() { 536 { 537 put("header1", Arrays.asList("value1", "value2")); // 7 + 6 + 6 = 19 538 put("header2", null); // 19 + 7 = 26 539 put("header3", Collections.emptyList()); // 26 + 7 + 0 = 33 540 put(null, Arrays.asList("")); // 33 + 0 + 0 = 33 541 } 542 }; 543 assertEquals(33, CronetUrlRequest.estimateHeadersSizeInBytes(headers)); 544 545 CronetUrlRequest.HeadersList headersList = new CronetUrlRequest.HeadersList(); 546 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>( 547 "header1", "value1") // 7 + 6 = 13 548 ); 549 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>( 550 "header1", "value2") // 13 + 7 + 6 = 26 551 ); 552 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>( 553 "header2", null) // 26 + 7 + 0 = 33 554 ); 555 headersList.add( 556 new AbstractMap.SimpleImmutableEntry<String, String>(null, "") // 33 + 0 + 0 = 33 557 ); 558 assertEquals(33, CronetUrlRequest.estimateHeadersSizeInBytes(asHeaderBlock(headersList))); 559 } 560 asHeaderBlock(List<Map.Entry<String, String>> headers)561 private static HeaderBlock asHeaderBlock(List<Map.Entry<String, String>> headers) { 562 return new HeaderBlockImpl(headers); 563 } 564 } 565