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.shared.testing; 17 18 import android.annotation.CallSuper; 19 import android.content.Context; 20 21 import androidx.test.platform.app.InstrumentationRegistry; 22 23 import org.junit.Rule; 24 import org.junit.Test; 25 26 /** 27 * Superclass for all device-side tests, it contains just the bare minimum features used by all 28 * tests. 29 */ 30 public abstract class DeviceSideTestCase extends SidelessTestCase { 31 32 private static final String TAG = DeviceSideTestCase.class.getSimpleName(); 33 34 private static final String REASON_SESSION_MANAGED_BY_RULE = 35 "mockito session is automatically managed by a @Rule"; 36 private static final String REASON_NO_TARGET_CONTEXT = 37 "tests should use mContext instead - if it needs the target context, please add to" 38 + " DeviceSideTestCase instead"; 39 protected static final String REASON_USE_FAKE_DEBUG_FLAGS_INSTEAD = 40 "should use mFakeDebugFlags and debugFlags rule instead"; 41 42 // TODO(b/335935200): This (and RavenwoodConfig) should be removed once Ravenwood starts 43 // using the package name from the build file. 44 private static final String RAVENWOOD_PACKAGE_NAME = "com.android.adservices.shared.tests"; 45 46 /** {@code logcat} tag. */ 47 protected final String mTag = getClass().getSimpleName(); 48 49 // NOTE: references below CANNOT be set when declared as the call to InstrumentationRegistry 50 // would fail when running on host / under Ravenwood 51 52 /** 53 * @deprecated use {@link #mContext} 54 */ 55 @Deprecated 56 protected static final Context sContext = 57 InstrumentationRegistry.getInstrumentation().getContext(); 58 59 /** 60 * Package name of the app being instrumented. 61 * 62 * @deprecated use {@link #mPackageName} instead. 63 */ 64 @Deprecated protected static final String sPackageName = sContext.getPackageName(); 65 66 /** 67 * Reference to the context of this test's instrumentation package (as defined by {@link 68 * android.app.Instrumentation#getContext()}) 69 */ 70 protected final Context mContext = sContext; 71 72 /** 73 * Package name of this test's instrumentation package (as defined by {@link 74 * android.app.Instrumentation#getContext()}) 75 */ 76 protected final String mPackageName = sPackageName; 77 78 // TODO(b/342639109): make sure it's the right order 79 @Rule(order = 0) 80 public final SdkLevelSupportRule sdkLevel = SdkLevelSupportRule.forAnyLevel(); 81 82 // TODO(b/342639109): set order 83 @Rule 84 public final ProcessLifeguardRule processLifeguard = 85 new ProcessLifeguardRule(ProcessLifeguardRule.Mode.IGNORE); 86 87 // TODO(b/361555631): merge 2 classes below into testDeviceSideTestCaseFixtures() and annotate 88 // it with @MetaTest 89 @Test 90 @Override testValidTestCaseFixtures()91 public final void testValidTestCaseFixtures() throws Exception { 92 assertValidTestCaseFixtures(); 93 } 94 95 @CallSuper 96 @Override assertValidTestCaseFixtures()97 protected void assertValidTestCaseFixtures() throws Exception { 98 super.assertValidTestCaseFixtures(); 99 100 assertTestClassHasNoFieldsFromSuperclass( 101 DeviceSideTestCase.class, 102 "mContext", 103 "mPackageName", 104 "mTag", 105 "ravenwood", 106 "sdkLevel", 107 "processLifeGuard", 108 "sContext", 109 "sPackageName", 110 "sRavenWood", 111 "RAVENWOOD_PACKAGE_NAME"); 112 assertTestClassHasNoSuchField( 113 "CONTEXT", 114 "should use existing mContext (or sContext when that's not possible) instead"); 115 assertTestClassHasNoSuchField( 116 "APPLICATION_CONTEXT", 117 "should use existing mContext (or sContext when that's not possible) instead"); 118 assertTestClassHasNoSuchField("context", "should use existing mContext instead"); 119 assertTestClassHasNoSuchField("mTargetContext", REASON_NO_TARGET_CONTEXT); 120 assertTestClassHasNoSuchField("mTargetPackageName", REASON_NO_TARGET_CONTEXT); 121 assertTestClassHasNoSuchField("sTargetContext", REASON_NO_TARGET_CONTEXT); 122 assertTestClassHasNoSuchField("sTargetPackageName", REASON_NO_TARGET_CONTEXT); 123 } 124 125 // NOTE: it's static so it can be used by other mockito-related superclasses, as often test 126 // cases are converted to use AdServicesMockitoTestCase and still defined the ExtendedMockito 127 // session - they should migrate to AdServicesExtendedMockitoTestCase instead. checkProhibitedMockitoFields( Class<T> superclass, T testInstance)128 protected static <T extends DeviceSideTestCase> void checkProhibitedMockitoFields( 129 Class<T> superclass, T testInstance) throws Exception { 130 // NOTE: same fields below are not defined (yet?) SharedExtendedMockitoTestCase or 131 // SharedMockitoTestCase, but they might; and even if they don't, this method is also used 132 // by the classes on AdServices (AdServicesMockitoTestCase / 133 // AdServicesExtendedMockitoTestCase) 134 testInstance.assertTestClassHasNoFieldsFromSuperclass( 135 superclass, 136 "mMockContext", 137 "mSpyContext", 138 "extendedMockito", 139 "errorLogUtilUsageRule", 140 "mocker", 141 "sInlineCleaner", 142 "sSpyContext" 143 // NOTE: mMockFlags is now checked by AdServicesUnitTestCase itself 144 ); 145 testInstance.assertTestClassHasNoSuchField( 146 "mContextMock", "should use existing mMockContext instead"); 147 testInstance.assertTestClassHasNoSuchField( 148 "mContextSpy", "should use existing mSpyContext instead"); 149 testInstance.assertTestClassHasNoSuchField("mockito", "already taken care by @Rule"); 150 testInstance.assertTestClassHasNoSuchField( 151 "mFlagsMock", "should use existing mMockFlags instead"); 152 testInstance.assertTestClassHasNoSuchField( 153 "mMockDebugFlags", REASON_USE_FAKE_DEBUG_FLAGS_INSTEAD); 154 testInstance.assertTestClassHasNoSuchField( 155 "mDebugFlagsMock", REASON_USE_FAKE_DEBUG_FLAGS_INSTEAD); 156 157 testInstance.assertTestClassHasNoSuchField( 158 "sMockFlags", "should use existing mMockFlags instead"); 159 testInstance.assertTestClassHasNoSuchField( 160 "mFlags", 161 superclass.getSimpleName() 162 + " already define a mMockFlags, and often subclasses define a @Mock" 163 + " mFlags; to avoid confusion, either use the existing mMockFlags, or" 164 + " create a non-mock instance like mFakeFlags"); 165 166 // Listed below are existing names for the extended mockito session on test classes that 167 // don't use the rule / superclass: 168 // TODO(b/368153625): should check for type instead 169 testInstance.assertTestClassHasNoSuchField( 170 "mStaticMockSession", REASON_SESSION_MANAGED_BY_RULE); 171 testInstance.assertTestClassHasNoSuchField( 172 "mMockitoSession", REASON_SESSION_MANAGED_BY_RULE); 173 testInstance.assertTestClassHasNoSuchField( 174 "mockitoSession", REASON_SESSION_MANAGED_BY_RULE); 175 testInstance.assertTestClassHasNoSuchField("session", REASON_SESSION_MANAGED_BY_RULE); 176 testInstance.assertTestClassHasNoSuchField( 177 "sStaticMockitoSession", REASON_SESSION_MANAGED_BY_RULE); 178 testInstance.assertTestClassHasNoSuchField( 179 "staticMockitoSession", REASON_SESSION_MANAGED_BY_RULE); 180 testInstance.assertTestClassHasNoSuchField( 181 "staticMockSession", REASON_SESSION_MANAGED_BY_RULE); 182 } 183 } 184