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