1 // Copyright 2023 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.telemetry; 6 7 import static com.google.common.truth.TruthJUnit.assume; 8 9 import static org.mockito.Mockito.never; 10 import static org.mockito.Mockito.spy; 11 import static org.mockito.Mockito.times; 12 import static org.mockito.Mockito.verify; 13 14 import android.os.Build; 15 import android.os.ConditionVariable; 16 17 import androidx.test.ext.junit.runners.AndroidJUnit4; 18 19 import org.junit.Before; 20 import org.junit.Rule; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.mockito.Mock; 24 import org.mockito.junit.MockitoJUnit; 25 import org.mockito.junit.MockitoRule; 26 27 import org.chromium.base.test.util.Batch; 28 import org.chromium.net.impl.CronetLogger.CronetEngineBuilderInfo; 29 import org.chromium.net.impl.CronetLogger.CronetSource; 30 import org.chromium.net.impl.CronetLogger.CronetTrafficInfo; 31 import org.chromium.net.impl.CronetLogger.CronetVersion; 32 33 @RunWith(AndroidJUnit4.class) 34 @Batch(Batch.UNIT_TESTS) 35 public final class CronetLoggerImplTest { CronetLoggerImplTest()36 public CronetLoggerImplTest() { 37 // CronetLoggerImpl only supports R+ 38 assume().that(Build.VERSION.SDK_INT).isAtLeast(Build.VERSION_CODES.R); 39 // TODO(crbug.com/1503671): Chromium Mockito doesn't work on Android 14. Remove this line 40 // once Mockito is fixed. 41 assume().that(Build.VERSION.SDK_INT).isLessThan(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); 42 } 43 44 @Rule public final MockitoRule mockito = MockitoJUnit.rule(); 45 46 private static final int CRONET_ENGINE_ID = 1; 47 private static final CronetSource SOURCE = CronetSource.CRONET_SOURCE_STATICALLY_LINKED; 48 49 private CronetLoggerImpl mCronetLoggerImpl; 50 51 @Mock CronetEngineBuilderInfo mBuilderInfo; 52 @Mock CronetVersion mVersion; 53 @Mock CronetTrafficInfo mTrafficInfo; 54 55 @Before setUp()56 public void setUp() { 57 mCronetLoggerImpl = spy(new CronetLoggerImpl(1)); 58 } 59 60 @Test testLogCronetEngineCreated_validInputs_shouldExecuteWrite()61 public void testLogCronetEngineCreated_validInputs_shouldExecuteWrite() { 62 mCronetLoggerImpl.logCronetEngineCreation(CRONET_ENGINE_ID, mBuilderInfo, mVersion, SOURCE); 63 64 verify(mCronetLoggerImpl, times(1)) 65 .writeCronetEngineCreation(CRONET_ENGINE_ID, mBuilderInfo, mVersion, SOURCE); 66 } 67 68 @Test testLogCronetEngineCreated_invalidInputs_shouldNotExecuteWrite()69 public void testLogCronetEngineCreated_invalidInputs_shouldNotExecuteWrite() { 70 mCronetLoggerImpl.logCronetEngineCreation(CRONET_ENGINE_ID, null, mVersion, SOURCE); 71 72 verify(mCronetLoggerImpl, never()) 73 .writeCronetEngineCreation(CRONET_ENGINE_ID, null, mVersion, SOURCE); 74 } 75 76 @Test testLogCronetTrafficInfo_validInputs_shouldExecuteWrite()77 public void testLogCronetTrafficInfo_validInputs_shouldExecuteWrite() { 78 mCronetLoggerImpl.logCronetTrafficInfo(CRONET_ENGINE_ID, mTrafficInfo); 79 80 verify(mCronetLoggerImpl, times(1)) 81 .writeCronetTrafficReported(CRONET_ENGINE_ID, mTrafficInfo, 0); 82 } 83 84 @Test testLogCronetTrafficInfo_invalidInputs_shouldNotExecuteWrite()85 public void testLogCronetTrafficInfo_invalidInputs_shouldNotExecuteWrite() { 86 mCronetLoggerImpl.logCronetTrafficInfo(CRONET_ENGINE_ID, null); 87 88 verify(mCronetLoggerImpl, never()).writeCronetTrafficReported(CRONET_ENGINE_ID, null, 0); 89 } 90 91 // TODO(b/309098875): the internal repo these tests were originally written in had the following 92 // tests: 93 // - logCronetTrafficInfo_samplesRateLimited_shouldBeZero 94 // - logCronetTrafficInfo_samplesRateLimited_shouldBe2 95 // - logCronetTrafficInfo_simultaneousLogs_shouldExecuteWriteOnce 96 // Problem is these tests used the Roboelectric ShadowSystemClock, which we can't easily use 97 // here. We should find a way to work around that. In the mean time, these tests are omitted. 98 99 @Test testLogCronetTrafficInfo_twoSamplesPerSecond_shouldLogTwice()100 public void testLogCronetTrafficInfo_twoSamplesPerSecond_shouldLogTwice() { 101 mCronetLoggerImpl = spy(new CronetLoggerImpl(2)); 102 103 mCronetLoggerImpl.logCronetTrafficInfo(CRONET_ENGINE_ID, mTrafficInfo); 104 mCronetLoggerImpl.logCronetTrafficInfo(CRONET_ENGINE_ID, mTrafficInfo); 105 mCronetLoggerImpl.logCronetTrafficInfo(CRONET_ENGINE_ID, mTrafficInfo); 106 107 verify(mCronetLoggerImpl, times(2)) 108 .writeCronetTrafficReported(CRONET_ENGINE_ID, mTrafficInfo, 0); 109 } 110 111 static class LogThread extends Thread { 112 final CronetLoggerImpl mLogger; 113 final ConditionVariable mRunBlocker; 114 final CronetTrafficInfo mTrafficInfo; 115 LogThread( CronetLoggerImpl logger, ConditionVariable runBlocker, CronetTrafficInfo trafficInfo)116 public LogThread( 117 CronetLoggerImpl logger, 118 ConditionVariable runBlocker, 119 CronetTrafficInfo trafficInfo) { 120 this.mLogger = logger; 121 this.mRunBlocker = runBlocker; 122 this.mTrafficInfo = trafficInfo; 123 } 124 125 @Override run()126 public void run() { 127 mRunBlocker.block(); 128 mLogger.logCronetTrafficInfo(CRONET_ENGINE_ID, mTrafficInfo); 129 } 130 } 131 } 132