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