1 /* 2 * Copyright (C) 2022 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.measurement; 17 18 import static org.junit.Assert.assertNotNull; 19 import static org.junit.Assert.assertNull; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyBoolean; 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.spy; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.pm.PackageManager; 34 import android.os.IBinder; 35 36 import androidx.test.core.app.ApplicationProvider; 37 38 import com.android.adservices.data.enrollment.EnrollmentDao; 39 import com.android.adservices.download.MddJobService; 40 import com.android.adservices.service.Flags; 41 import com.android.adservices.service.FlagsFactory; 42 import com.android.adservices.service.common.AppImportanceFilter; 43 import com.android.adservices.service.common.PackageChangedReceiver; 44 import com.android.adservices.service.consent.AdServicesApiConsent; 45 import com.android.adservices.service.consent.AdServicesApiType; 46 import com.android.adservices.service.consent.ConsentManager; 47 import com.android.adservices.service.enrollment.EnrollmentData; 48 import com.android.adservices.service.measurement.DeleteExpiredJobService; 49 import com.android.adservices.service.measurement.DeleteUninstalledJobService; 50 import com.android.adservices.service.measurement.MeasurementImpl; 51 import com.android.adservices.service.measurement.attribution.AttributionJobService; 52 import com.android.adservices.service.measurement.registration.AsyncRegistrationQueueJobService; 53 import com.android.adservices.service.measurement.reporting.AggregateFallbackReportingJobService; 54 import com.android.adservices.service.measurement.reporting.AggregateReportingJobService; 55 import com.android.adservices.service.measurement.reporting.EventFallbackReportingJobService; 56 import com.android.adservices.service.measurement.reporting.EventReportingJobService; 57 import com.android.compatibility.common.util.TestUtils; 58 import com.android.dx.mockito.inline.extended.ExtendedMockito; 59 60 import org.junit.Before; 61 import org.junit.Test; 62 import org.mockito.Mock; 63 import org.mockito.MockitoAnnotations; 64 import org.mockito.MockitoSession; 65 import org.mockito.quality.Strictness; 66 67 import java.util.List; 68 69 /** Unit test for {@link com.android.adservices.measurement.MeasurementService}. */ 70 public class MeasurementServiceTest { 71 @Mock ConsentManager mMockConsentManager; 72 @Mock Flags mMockFlags; 73 @Mock MeasurementImpl mMockMeasurementImpl; 74 @Mock EnrollmentDao mMockEnrollmentDao; 75 @Mock AppImportanceFilter mMockAppImportanceFilter; 76 77 private static final EnrollmentData ENROLLMENT = 78 new EnrollmentData.Builder() 79 .setEnrollmentId("E1") 80 .setCompanyId("1001") 81 .setSdkNames("sdk1") 82 .setAttributionSourceRegistrationUrl(List.of("https://test.com/source")) 83 .setAttributionTriggerRegistrationUrl(List.of("https://test.com/trigger")) 84 .setAttributionReportingUrl(List.of("https://test.com")) 85 .setRemarketingResponseBasedRegistrationUrl(List.of("https://test.com")) 86 .setEncryptionKeyUrl(List.of("https://test.com/keys")) 87 .build(); 88 89 /** Setup for tests */ 90 @Before setup()91 public void setup() { 92 MockitoAnnotations.initMocks(this); 93 } 94 95 /** Test kill switch off with consent given */ 96 @Test testBindableMeasurementService_killSwitchOff_gaUxDisabled_consentGiven()97 public void testBindableMeasurementService_killSwitchOff_gaUxDisabled_consentGiven() 98 throws Exception { 99 runWithMocks( 100 /* killSwitchOff */ false, 101 /* consentGiven */ true, 102 /* isGaUxEnabled */ false, 103 () -> { 104 // Execute 105 final IBinder binder = onCreateAndOnBindService(); 106 107 // Verification 108 assertNotNull(binder); 109 verify(mMockConsentManager, times(1)).getConsent(); 110 ExtendedMockito.verify( 111 () -> PackageChangedReceiver.enableReceiver(any(Context.class), any())); 112 assertJobScheduled(/* timesCalled */ 1); 113 }); 114 } 115 116 /** Test kill switch off with consent revoked */ 117 @Test testBindableMeasurementService_killSwitchOff_gaUxDisabled_consentRevoked()118 public void testBindableMeasurementService_killSwitchOff_gaUxDisabled_consentRevoked() 119 throws Exception { 120 runWithMocks( 121 /* killSwitchOff */ false, 122 /* consentRevoked */ false, 123 /* isGaUxEnabled */ false, 124 () -> { 125 // Execute 126 final IBinder binder = onCreateAndOnBindService(); 127 128 // Verification 129 assertNotNull(binder); 130 verify(mMockConsentManager, times(1)).getConsent(); 131 assertJobScheduled(/* timesCalled */ 0); 132 }); 133 } 134 135 /** Test kill switch on */ 136 @Test testBindableMeasurementService_killSwitchOn_gaUxDisabled()137 public void testBindableMeasurementService_killSwitchOn_gaUxDisabled() throws Exception { 138 runWithMocks( 139 /* killSwitchOn */ true, 140 /* consentGiven */ true, 141 /* isGaUxEnabled */ false, 142 () -> { 143 // Execute 144 final IBinder binder = onCreateAndOnBindService(); 145 146 // Verification 147 assertNull(binder); 148 verify(mMockConsentManager, never()).getConsent(); 149 assertJobScheduled(/* timesCalled */ 0); 150 }); 151 } 152 153 /** Test kill switch off with consent given */ 154 @Test testBindableMeasurementService_killSwitchOff_gaUxEnabled_consentGiven()155 public void testBindableMeasurementService_killSwitchOff_gaUxEnabled_consentGiven() 156 throws Exception { 157 runWithMocks( 158 /* killSwitchOff */ false, 159 /* consentGiven */ true, 160 /* isGaUxEnabled */ true, 161 () -> { 162 // Execute 163 final IBinder binder = onCreateAndOnBindService(); 164 165 // Verification 166 assertNotNull(binder); 167 verify(mMockConsentManager, never()).getConsent(); 168 verify(mMockConsentManager, times(1)) 169 .getConsent(eq(AdServicesApiType.MEASUREMENTS)); 170 ExtendedMockito.verify( 171 () -> PackageChangedReceiver.enableReceiver(any(Context.class), any())); 172 assertJobScheduled(/* timesCalled */ 1); 173 }); 174 } 175 176 /** Test kill switch off with consent revoked */ 177 @Test testBindableMeasurementService_killSwitchOff_gaUxEnabled_consentRevoked()178 public void testBindableMeasurementService_killSwitchOff_gaUxEnabled_consentRevoked() 179 throws Exception { 180 runWithMocks( 181 /* killSwitchOff */ false, 182 /* consentRevoked */ false, 183 /* isGaUxEnabled */ true, 184 () -> { 185 // Execute 186 final IBinder binder = onCreateAndOnBindService(); 187 188 // Verification 189 assertNotNull(binder); 190 verify(mMockConsentManager, never()).getConsent(); 191 verify(mMockConsentManager, times(1)) 192 .getConsent(eq(AdServicesApiType.MEASUREMENTS)); 193 assertJobScheduled(/* timesCalled */ 0); 194 }); 195 } 196 197 /** Test kill switch on */ 198 @Test testBindableMeasurementService_killSwitchOn_gaUxEnabled()199 public void testBindableMeasurementService_killSwitchOn_gaUxEnabled() throws Exception { 200 runWithMocks( 201 /* killSwitchOn */ true, 202 /* consentGiven */ true, 203 /* isGaUxEnabled */ false, 204 () -> { 205 // Execute 206 final IBinder binder = onCreateAndOnBindService(); 207 208 // Verification 209 assertNull(binder); 210 verify(mMockConsentManager, never()).getConsent(); 211 verify(mMockConsentManager, never()).getConsent(any()); 212 assertJobScheduled(/* timesCalled */ 0); 213 }); 214 } 215 getIntentForMeasurementService()216 private Intent getIntentForMeasurementService() { 217 return new Intent(ApplicationProvider.getApplicationContext(), MeasurementService.class); 218 } 219 onCreateAndOnBindService()220 private IBinder onCreateAndOnBindService() { 221 MeasurementService spyMeasurementService = spy(new MeasurementService()); 222 doReturn(mock(PackageManager.class)).when(spyMeasurementService).getPackageManager(); 223 spyMeasurementService.onCreate(); 224 return spyMeasurementService.onBind(getIntentForMeasurementService()); 225 } 226 runWithMocks( boolean killSwitchStatus, boolean consentStatus, boolean isGaUxEnabled, TestUtils.RunnableWithThrow execute)227 private void runWithMocks( 228 boolean killSwitchStatus, 229 boolean consentStatus, 230 boolean isGaUxEnabled, 231 TestUtils.RunnableWithThrow execute) 232 throws Exception { 233 // Start a mockitoSession to mock static method 234 final MockitoSession session = 235 ExtendedMockito.mockitoSession() 236 .spyStatic(AggregateReportingJobService.class) 237 .spyStatic(AggregateFallbackReportingJobService.class) 238 .spyStatic(AppImportanceFilter.class) 239 .spyStatic(AttributionJobService.class) 240 .spyStatic(ConsentManager.class) 241 .spyStatic(EnrollmentDao.class) 242 .spyStatic(EventReportingJobService.class) 243 .spyStatic(PackageChangedReceiver.class) 244 .spyStatic(EventFallbackReportingJobService.class) 245 .spyStatic(DeleteExpiredJobService.class) 246 .spyStatic(DeleteUninstalledJobService.class) 247 .spyStatic(MddJobService.class) 248 .spyStatic(FlagsFactory.class) 249 .spyStatic(MeasurementImpl.class) 250 .spyStatic(AsyncRegistrationQueueJobService.class) 251 .strictness(Strictness.LENIENT) 252 .startMocking(); 253 try { 254 doReturn(killSwitchStatus).when(mMockFlags).getMeasurementKillSwitch(); 255 doReturn(isGaUxEnabled).when(mMockFlags).getGaUxFeatureEnabled(); 256 257 ExtendedMockito.doReturn(mMockFlags).when(FlagsFactory::getFlags); 258 259 ExtendedMockito.doReturn(mMockConsentManager) 260 .when(() -> ConsentManager.getInstance(any())); 261 262 final AdServicesApiConsent mockConsent = mock(AdServicesApiConsent.class); 263 doReturn(consentStatus).when(mockConsent).isGiven(); 264 265 if (isGaUxEnabled) { 266 doReturn(mockConsent) 267 .when(mMockConsentManager) 268 .getConsent(eq(AdServicesApiType.MEASUREMENTS)); 269 } else { 270 doReturn(mockConsent).when(mMockConsentManager).getConsent(); 271 } 272 273 ExtendedMockito.doReturn(mMockEnrollmentDao) 274 .when(() -> EnrollmentDao.getInstance(any())); 275 doReturn(ENROLLMENT) 276 .when(mMockEnrollmentDao) 277 .getEnrollmentDataFromMeasurementUrl(any()); 278 279 ExtendedMockito.doReturn(mMockMeasurementImpl) 280 .when(() -> MeasurementImpl.getInstance(any())); 281 282 ExtendedMockito.doReturn(mMockAppImportanceFilter) 283 .when(() -> AppImportanceFilter.create(any(), anyInt(), any())); 284 285 ExtendedMockito.doReturn(true) 286 .when(() -> PackageChangedReceiver.enableReceiver(any(Context.class), any())); 287 ExtendedMockito.doNothing() 288 .when(() -> AggregateReportingJobService.scheduleIfNeeded(any(), anyBoolean())); 289 ExtendedMockito.doNothing() 290 .when( 291 () -> 292 AggregateFallbackReportingJobService.scheduleIfNeeded( 293 any(), anyBoolean())); 294 ExtendedMockito.doNothing() 295 .when(() -> AttributionJobService.scheduleIfNeeded(any(), anyBoolean())); 296 297 ExtendedMockito.doNothing() 298 .when(() -> EventReportingJobService.scheduleIfNeeded(any(), anyBoolean())); 299 ExtendedMockito.doNothing() 300 .when( 301 () -> 302 EventFallbackReportingJobService.scheduleIfNeeded( 303 any(), anyBoolean())); 304 ExtendedMockito.doNothing() 305 .when(() -> DeleteExpiredJobService.scheduleIfNeeded(any(), anyBoolean())); 306 ExtendedMockito.doNothing() 307 .when(() -> DeleteUninstalledJobService.scheduleIfNeeded(any(), anyBoolean())); 308 ExtendedMockito.doReturn(true) 309 .when(() -> MddJobService.scheduleIfNeeded(any(), anyBoolean())); 310 ExtendedMockito.doNothing() 311 .when( 312 () -> 313 AsyncRegistrationQueueJobService.scheduleIfNeeded( 314 any(), anyBoolean())); 315 316 // Execute 317 execute.run(); 318 } finally { 319 session.finishMocking(); 320 } 321 } 322 assertJobScheduled(int timesCalled)323 private void assertJobScheduled(int timesCalled) { 324 ExtendedMockito.verify( 325 () -> AggregateReportingJobService.scheduleIfNeeded(any(), anyBoolean()), 326 times(timesCalled)); 327 ExtendedMockito.verify( 328 () -> AggregateFallbackReportingJobService.scheduleIfNeeded(any(), anyBoolean()), 329 times(timesCalled)); 330 ExtendedMockito.verify( 331 () -> AttributionJobService.scheduleIfNeeded(any(), anyBoolean()), 332 times(timesCalled)); 333 ExtendedMockito.verify( 334 () -> EventReportingJobService.scheduleIfNeeded(any(), anyBoolean()), 335 times(timesCalled)); 336 ExtendedMockito.verify( 337 () -> EventFallbackReportingJobService.scheduleIfNeeded(any(), anyBoolean()), 338 times(timesCalled)); 339 ExtendedMockito.verify( 340 () -> DeleteExpiredJobService.scheduleIfNeeded(any(), anyBoolean()), 341 times(timesCalled)); 342 ExtendedMockito.verify( 343 () -> DeleteUninstalledJobService.scheduleIfNeeded(any(), anyBoolean()), 344 times(timesCalled)); 345 ExtendedMockito.verify( 346 () -> MddJobService.scheduleIfNeeded(any(), anyBoolean()), times(timesCalled)); 347 ExtendedMockito.verify( 348 () -> AsyncRegistrationQueueJobService.scheduleIfNeeded(any(), anyBoolean()), 349 times(timesCalled)); 350 } 351 } 352