1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.adservices.common; 17 18 import static com.android.adservices.mockito.ExtendedMockitoInlineCleanerRule.Mode.CLEAR_AFTER_TEST_CLASS; 19 import static com.android.adservices.service.DebugFlagsConstants.KEY_CONSENT_NOTIFICATION_DEBUG_MODE; 20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 21 22 import static org.mockito.ArgumentMatchers.any; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 25 import android.annotation.CallSuper; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 31 import com.android.adservices.common.AdServicesMockerLessExtendedMockitoTestCase.InternalMocker; 32 import com.android.adservices.common.logging.AdServicesLoggingUsageRule; 33 import com.android.adservices.common.logging.annotations.ExpectErrorLogUtilCall; 34 import com.android.adservices.common.logging.annotations.ExpectErrorLogUtilWithExceptionCall; 35 import com.android.adservices.common.logging.annotations.SetErrorLogUtilDefaultParams; 36 import com.android.adservices.errorlogging.ErrorLogUtil; 37 import com.android.adservices.mockito.AdServicesExtendedMockitoMocker; 38 import com.android.adservices.mockito.AdServicesExtendedMockitoRule; 39 import com.android.adservices.mockito.AdServicesFlagsMocker; 40 import com.android.adservices.mockito.AdServicesMockitoFlagsMocker; 41 import com.android.adservices.mockito.AdServicesMockitoMocker; 42 import com.android.adservices.mockito.AdServicesPragmaticMocker; 43 import com.android.adservices.mockito.AdServicesStaticMocker; 44 import com.android.adservices.mockito.AndroidExtendedMockitoMocker; 45 import com.android.adservices.mockito.AndroidMocker; 46 import com.android.adservices.mockito.AndroidMockitoMocker; 47 import com.android.adservices.mockito.AndroidStaticMocker; 48 import com.android.adservices.mockito.ExtendedMockitoInlineCleanerRule; 49 import com.android.adservices.mockito.ExtendedMockitoInlineCleanerRule.ClearInlineMocksMode; 50 import com.android.adservices.mockito.LogInterceptor; 51 import com.android.adservices.mockito.SharedMocker; 52 import com.android.adservices.mockito.SharedMockitoMocker; 53 import com.android.adservices.mockito.StaticClassChecker; 54 import com.android.adservices.service.DebugFlags; 55 import com.android.adservices.service.Flags; 56 import com.android.adservices.service.stats.AdServicesLogger; 57 import com.android.adservices.service.stats.AdServicesLoggerImpl; 58 import com.android.adservices.service.stats.ApiCallStats; 59 import com.android.adservices.shared.spe.logging.JobServiceLogger; 60 import com.android.adservices.shared.testing.JobServiceLoggingCallback; 61 import com.android.adservices.shared.testing.concurrency.ResultSyncCallback; 62 import com.android.adservices.shared.util.Clock; 63 import com.android.adservices.spe.AdServicesJobScheduler; 64 import com.android.adservices.spe.AdServicesJobServiceFactory; 65 import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic; 66 67 import org.junit.ClassRule; 68 import org.junit.Rule; 69 import org.mockito.Mock; 70 import org.mockito.Spy; 71 import org.mockito.quality.Strictness; 72 73 /** 74 * Base class for {@link AdServicesExtendedMockitoTestCase}, but leaving a hook ({@link 75 * #newMocker(AdServicesExtendedMockitoRule, Flags)} for subclasses to provide the {@code mocker} 76 * object. 77 * 78 * @param <M> mocker type 79 */ 80 @ClearInlineMocksMode(CLEAR_AFTER_TEST_CLASS) 81 @MockStatic(ErrorLogUtil.class) 82 public abstract class AdServicesMockerLessExtendedMockitoTestCase<M extends InternalMocker> 83 extends AdServicesUnitTestCase { 84 85 @Mock protected Context mMockContext; 86 87 /** Spy the {@link AdServicesUnitTestCase#mContext} */ 88 @Spy protected final Context mSpyContext = mContext; 89 90 // NOTE: must use CLEAR_AFTER_TEST_CLASS by default (defined as a class annotation, so it's used 91 // by both ExtendedMockitoInlineCleanerRule and AdServicesExtendedMockitoRule), as some tests 92 // performing complicated static class initialization on @Before methods, which often cause test 93 // failure when called after the mocks are cleared (for example, DialogFragmentTest would fail 94 // after the first method was executed) 95 @ClassRule 96 public static final ExtendedMockitoInlineCleanerRule sInlineCleaner = 97 new ExtendedMockitoInlineCleanerRule(); 98 99 @Rule(order = 10) 100 public final AdServicesExtendedMockitoRule extendedMockito = getAdServicesExtendedMockitoRule(); 101 102 /** 103 * Scans for usage of {@code ErrorLogUtil.e(int, int)} and {@code ErrorLogUtil.e(Throwable, int 104 * int)} invocations. Fails the test if calls haven't been verified using {@link 105 * ExpectErrorLogUtilCall} and/or {@link ExpectErrorLogUtilWithExceptionCall}. 106 * 107 * <p>Also see {@link SetErrorLogUtilDefaultParams} to set common default logging params. 108 */ 109 // TODO(b/342639109): Fix the order of the rules. 110 @Rule(order = 11) 111 public final AdServicesLoggingUsageRule errorLogUtilUsageRule = 112 AdServicesLoggingUsageRule.errorLogUtilUsageRule(); 113 114 /** Provides common expectations. */ 115 public final M mocker = newMocker(extendedMockito, mMockFlags); 116 117 /** 118 * Gets the {@link AdServicesExtendedMockitoRule} that will be set as the {@code 119 * extendedMockito} rule. 120 * 121 * <p>By default returns a rule created using {@link 122 * #newDefaultAdServicesExtendedMockitoRuleBuilder()}, which is enough for most tests. But 123 * subclasses can override it to handle special cases that cannot be configured through 124 * annotations, like : 125 * 126 * <ul> 127 * <li>Changing the strictness mode. 128 * <li>Setting the {@link com.android.modules.utils.testing.StaticMockFixture}s. 129 * </ul> 130 */ getAdServicesExtendedMockitoRule()131 protected AdServicesExtendedMockitoRule getAdServicesExtendedMockitoRule() { 132 return newDefaultAdServicesExtendedMockitoRuleBuilder().build(); 133 } 134 135 /** Returns the object that will be referenced by {@code mocker}. */ newMocker(AdServicesExtendedMockitoRule rule, Flags mockFlags)136 protected abstract M newMocker(AdServicesExtendedMockitoRule rule, Flags mockFlags); 137 138 /** 139 * Creates a new {@link AdServicesExtendedMockitoRule.Builder} with the default properties. 140 * 141 * @return builder that initialize mocks for the class, using {@link Strictness.LENIENT lenient} 142 * mode. 143 */ 144 protected final AdServicesExtendedMockitoRule.Builder newDefaultAdServicesExtendedMockitoRuleBuilder()145 newDefaultAdServicesExtendedMockitoRuleBuilder() { 146 return new AdServicesExtendedMockitoRule.Builder(this).setStrictness(Strictness.LENIENT); 147 } 148 149 // TODO(b/361555631): rename to testAdServicesExtendedMockitoTestCaseFixtures() and annotate 150 // it with @MetaTest 151 @CallSuper 152 @Override assertValidTestCaseFixtures()153 protected void assertValidTestCaseFixtures() throws Exception { 154 super.assertValidTestCaseFixtures(); 155 156 checkProhibitedMockitoFields(AdServicesMockerLessExtendedMockitoTestCase.class, this); 157 } 158 159 /** 160 * @deprecated TODO(b/338067482): temporary method, ideally it should be inlined or replaced 161 * by @EnableDebugFlag / @DisableDebugFlag; if not, then it should be unit tested (on 162 * AdServicesExtendedMockitoTestCaseTest) 163 */ 164 @Deprecated mockGetConsentNotificationDebugMode(boolean mode)165 protected void mockGetConsentNotificationDebugMode(boolean mode) { 166 mLog.v( 167 "mockGetConsentNotificationDebugMode(%b): delegating to debugFlags rule (%s)", 168 mode, debugFlags); 169 debugFlags.setDebugFlag(KEY_CONSENT_NOTIFICATION_DEBUG_MODE, mode); 170 } 171 172 private static final String REASON_SESSION_MANAGED_BY_RULE = 173 "mockito session is automatically managed by a @Rule"; 174 175 public abstract static class InternalMocker 176 implements AndroidMocker, 177 AndroidStaticMocker, 178 AdServicesPragmaticMocker, 179 AdServicesFlagsMocker, 180 AdServicesStaticMocker, 181 SharedMocker { 182 183 private final AndroidMocker mAndroidMocker = new AndroidMockitoMocker(); 184 private final SharedMocker mSharedMocker = new SharedMockitoMocker(); 185 private final AdServicesPragmaticMocker mAdServicesMocker = new AdServicesMockitoMocker(); 186 @Nullable private final AdServicesFlagsMocker mAdServicesFlagsMocker; 187 @Nullable private final AndroidStaticMocker mAndroidStaticMocker; 188 @Nullable private final AdServicesStaticMocker mAdServicesStaticMocker; 189 InternalMocker(StaticClassChecker checker, Flags flags)190 protected InternalMocker(StaticClassChecker checker, Flags flags) { 191 if (checker != null) { 192 mAndroidStaticMocker = new AndroidExtendedMockitoMocker(checker); 193 mAdServicesStaticMocker = new AdServicesExtendedMockitoMocker(checker); 194 } else { 195 mAndroidStaticMocker = null; 196 mAdServicesStaticMocker = null; 197 } 198 mAdServicesFlagsMocker = flags != null ? new AdServicesMockitoFlagsMocker(flags) : null; 199 } 200 201 // AndroidMocker methods 202 203 @Override mockQueryIntentService(PackageManager mockPm, ResolveInfo... resolveInfos)204 public void mockQueryIntentService(PackageManager mockPm, ResolveInfo... resolveInfos) { 205 mAndroidMocker.mockQueryIntentService(mockPm, resolveInfos); 206 } 207 208 @Override mockGetApplicationContext(Context mockContext, Context appContext)209 public void mockGetApplicationContext(Context mockContext, Context appContext) { 210 mAndroidMocker.mockGetApplicationContext(mockContext, appContext); 211 } 212 213 // AndroidStaticMocker methods 214 215 @Override mockGetCallingUidOrThrow(int uid)216 public void mockGetCallingUidOrThrow(int uid) { 217 mAndroidStaticMocker.mockGetCallingUidOrThrow(uid); 218 } 219 220 @Override mockGetCallingUidOrThrow()221 public void mockGetCallingUidOrThrow() { 222 mAndroidStaticMocker.mockGetCallingUidOrThrow(); 223 } 224 225 @Override mockIsAtLeastR(boolean isIt)226 public void mockIsAtLeastR(boolean isIt) { 227 mAndroidStaticMocker.mockIsAtLeastR(isIt); 228 } 229 230 @Override mockIsAtLeastS(boolean isIt)231 public void mockIsAtLeastS(boolean isIt) { 232 mAndroidStaticMocker.mockIsAtLeastS(isIt); 233 } 234 235 @Override mockIsAtLeastT(boolean isIt)236 public void mockIsAtLeastT(boolean isIt) { 237 mAndroidStaticMocker.mockIsAtLeastT(isIt); 238 } 239 240 @Override mockIsAtLeastV(boolean isIt)241 public void mockIsAtLeastV(boolean isIt) { 242 mAndroidStaticMocker.mockIsAtLeastV(isIt); 243 } 244 245 @Override mockSdkLevelR()246 public void mockSdkLevelR() { 247 mAndroidStaticMocker.mockSdkLevelR(); 248 } 249 250 @Override mockSdkLevelS()251 public void mockSdkLevelS() { 252 mAndroidStaticMocker.mockSdkLevelS(); 253 } 254 255 @Override mockGetCurrentUser(int user)256 public void mockGetCurrentUser(int user) { 257 mAndroidStaticMocker.mockGetCurrentUser(user); 258 } 259 260 @Override interceptLogD(String tag)261 public LogInterceptor interceptLogD(String tag) { 262 return mAndroidStaticMocker.interceptLogD(tag); 263 } 264 265 @Override interceptLogV(String tag)266 public LogInterceptor interceptLogV(String tag) { 267 return mAndroidStaticMocker.interceptLogV(tag); 268 } 269 270 @Override interceptLogE(String tag)271 public LogInterceptor interceptLogE(String tag) { 272 return mAndroidStaticMocker.interceptLogE(tag); 273 } 274 275 // AdServicesPragmaticMocker methods 276 277 @Override mockLogApiCallStats( AdServicesLogger adServicesLogger)278 public ResultSyncCallback<ApiCallStats> mockLogApiCallStats( 279 AdServicesLogger adServicesLogger) { 280 return mAdServicesMocker.mockLogApiCallStats(adServicesLogger); 281 } 282 283 @Override mockLogApiCallStats( AdServicesLogger adServicesLogger, long timeoutMs)284 public ResultSyncCallback<ApiCallStats> mockLogApiCallStats( 285 AdServicesLogger adServicesLogger, long timeoutMs) { 286 return mAdServicesMocker.mockLogApiCallStats(adServicesLogger, timeoutMs); 287 } 288 289 // AdServicesFlagsMocker methods 290 @Override mockGetBackgroundJobsLoggingKillSwitch(boolean value)291 public void mockGetBackgroundJobsLoggingKillSwitch(boolean value) { 292 mAdServicesFlagsMocker.mockGetBackgroundJobsLoggingKillSwitch(value); 293 } 294 295 @Override mockGetCobaltLoggingEnabled(boolean value)296 public void mockGetCobaltLoggingEnabled(boolean value) { 297 mAdServicesFlagsMocker.mockGetCobaltLoggingEnabled(value); 298 } 299 300 @Override mockGetAppNameApiErrorCobaltLoggingEnabled(boolean value)301 public void mockGetAppNameApiErrorCobaltLoggingEnabled(boolean value) { 302 mAdServicesFlagsMocker.mockGetAppNameApiErrorCobaltLoggingEnabled(value); 303 } 304 305 @Override mockGetEnableApiCallResponseLoggingEnabled(boolean value)306 public void mockGetEnableApiCallResponseLoggingEnabled(boolean value) { 307 mAdServicesFlagsMocker.mockGetEnableApiCallResponseLoggingEnabled(value); 308 } 309 310 @Override mockGetAdservicesReleaseStageForCobalt(String stage)311 public void mockGetAdservicesReleaseStageForCobalt(String stage) { 312 mAdServicesFlagsMocker.mockGetAdservicesReleaseStageForCobalt(stage); 313 } 314 315 @Override mockAllCobaltLoggingFlags(boolean enabled)316 public void mockAllCobaltLoggingFlags(boolean enabled) { 317 mAdServicesFlagsMocker.mockAllCobaltLoggingFlags(enabled); 318 } 319 320 // AdServicesStaticMocker methods 321 322 @Override mockGetFlags(Flags mockedFlags)323 public void mockGetFlags(Flags mockedFlags) { 324 mAdServicesStaticMocker.mockGetFlags(mockedFlags); 325 } 326 327 @Override mockGetDebugFlags(DebugFlags mockedDebugFlags)328 public void mockGetDebugFlags(DebugFlags mockedDebugFlags) { 329 mAdServicesStaticMocker.mockGetDebugFlags(mockedDebugFlags); 330 } 331 332 @Override mockSpeJobScheduler(AdServicesJobScheduler mockedAdServicesJobScheduler)333 public void mockSpeJobScheduler(AdServicesJobScheduler mockedAdServicesJobScheduler) { 334 mAdServicesStaticMocker.mockSpeJobScheduler(mockedAdServicesJobScheduler); 335 } 336 337 @Override mockAdServicesJobServiceFactory( AdServicesJobServiceFactory mockedAdServicesJobServiceFactory)338 public void mockAdServicesJobServiceFactory( 339 AdServicesJobServiceFactory mockedAdServicesJobServiceFactory) { 340 mAdServicesStaticMocker.mockAdServicesJobServiceFactory( 341 mockedAdServicesJobServiceFactory); 342 } 343 344 @Override mockAdServicesLoggerImpl(AdServicesLoggerImpl mockedAdServicesLoggerImpl)345 public void mockAdServicesLoggerImpl(AdServicesLoggerImpl mockedAdServicesLoggerImpl) { 346 mAdServicesStaticMocker.mockAdServicesLoggerImpl(mockedAdServicesLoggerImpl); 347 } 348 349 // SharedMocker methods 350 351 @Override setApplicationContextSingleton()352 public Context setApplicationContextSingleton() { 353 return mSharedMocker.setApplicationContextSingleton(); 354 } 355 356 @Override mockSetApplicationContextSingleton(Context context)357 public void mockSetApplicationContextSingleton(Context context) { 358 mSharedMocker.mockSetApplicationContextSingleton(context); 359 } 360 361 @Override syncRecordOnStopJob(JobServiceLogger logger)362 public JobServiceLoggingCallback syncRecordOnStopJob(JobServiceLogger logger) { 363 return mSharedMocker.syncRecordOnStopJob(logger); 364 } 365 366 @Override mockCurrentTimeMillis(Clock mockClock, long... mockedValues)367 public void mockCurrentTimeMillis(Clock mockClock, long... mockedValues) { 368 mSharedMocker.mockCurrentTimeMillis(mockClock, mockedValues); 369 } 370 371 @Override mockElapsedRealtime(Clock mockClock, long... mockedValues)372 public void mockElapsedRealtime(Clock mockClock, long... mockedValues) { 373 mSharedMocker.mockElapsedRealtime(mockClock, mockedValues); 374 } 375 } 376 377 /** 378 * @deprecated Use {@link AdServicesLoggingUsageRule} to verify {@link ErrorLogUtil#e()} calls. 379 * Tests using this rule should NOT mock {@link ErrorLogUtil#e()} calls as it's taken care 380 * of under the hood. 381 */ 382 // TODO(b/359964245): final use case that needs some investigation before this can be deleted 383 @Deprecated doNothingOnErrorLogUtilError()384 protected final void doNothingOnErrorLogUtilError() { 385 doNothing().when(() -> ErrorLogUtil.e(any(), anyInt(), anyInt())); 386 doNothing().when(() -> ErrorLogUtil.e(anyInt(), anyInt())); 387 } 388 } 389