diff options
Diffstat (limited to 'adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AsyncRegistrationQueueJobServiceTest.java')
-rw-r--r-- | adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AsyncRegistrationQueueJobServiceTest.java | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AsyncRegistrationQueueJobServiceTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AsyncRegistrationQueueJobServiceTest.java new file mode 100644 index 0000000000..36249ea321 --- /dev/null +++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AsyncRegistrationQueueJobServiceTest.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.adservices.service.measurement; + +import static com.android.adservices.service.AdServicesConfig.ASYNC_REGISTRATION_QUEUE_JOB_ID; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.content.Context; + +import com.android.adservices.data.enrollment.EnrollmentDao; +import com.android.adservices.data.measurement.DatastoreManager; +import com.android.adservices.data.measurement.DatastoreManagerFactory; +import com.android.adservices.service.Flags; +import com.android.adservices.service.FlagsFactory; +import com.android.adservices.service.stats.AdServicesLoggerImpl; +import com.android.compatibility.common.util.TestUtils; +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.util.Optional; + +public class AsyncRegistrationQueueJobServiceTest { + + private static final long WAIT_IN_MILLIS = 50L; + private JobScheduler mMockJobScheduler; + private AsyncRegistrationQueueJobService mSpyService; + private DatastoreManager mMockDatastoreManager; + + @Before + public void setUp() { + mSpyService = spy(new AsyncRegistrationQueueJobService()); + mMockJobScheduler = mock(JobScheduler.class); + } + + @Test + public void onStartJob_killSwitchOn() throws Exception { + runWithMocks( + () -> { + // Setup + enableKillSwitch(); + + // Execute + boolean result = mSpyService.onStartJob(mock(JobParameters.class)); + + // Validate + assertFalse(result); + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + verify(mSpyService, times(1)).jobFinished(any(), eq(false)); + verify(mMockJobScheduler, times(1)).cancel(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + @Test + public void onStartJob_killSwitchOff() throws Exception { + runWithMocks( + () -> { + // Setup + disableKillSwitch(); + ExtendedMockito.doNothing() + .when( + () -> + AsyncRegistrationQueueJobService.scheduleIfNeeded( + any(), anyBoolean())); + + // Execute + boolean result = mSpyService.onStartJob(mock(JobParameters.class)); + + // Validate + assertTrue(result); + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + ExtendedMockito.verify(mSpyService, times(1)).jobFinished(any(), anyBoolean()); + verify(mMockJobScheduler, never()).cancel(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + @Test + public void scheduleIfNeeded_killSwitchOn_dontSchedule() throws Exception { + runWithMocks( + () -> { + // Setup + enableKillSwitch(); + + final Context mockContext = mock(Context.class); + doReturn(mMockJobScheduler) + .when(mockContext) + .getSystemService(JobScheduler.class); + final JobInfo mockJobInfo = mock(JobInfo.class); + doReturn(mockJobInfo) + .when(mMockJobScheduler) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + + // Execute + AsyncRegistrationQueueJobService.scheduleIfNeeded( + mockContext, /* forceSchedule = */ false); + + // Validate + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + ExtendedMockito.verify( + () -> AsyncRegistrationQueueJobService.schedule(any(), any()), never()); + verify(mMockJobScheduler, never()) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + @Test + public void scheduleIfNeeded_killSwitchOff_previouslyExecuted_dontForceSchedule_dontSchedule() + throws Exception { + runWithMocks( + () -> { + // Setup + disableKillSwitch(); + + final Context mockContext = mock(Context.class); + doReturn(mMockJobScheduler) + .when(mockContext) + .getSystemService(JobScheduler.class); + final JobInfo mockJobInfo = mock(JobInfo.class); + doReturn(mockJobInfo) + .when(mMockJobScheduler) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + + // Execute + AsyncRegistrationQueueJobService.scheduleIfNeeded( + mockContext, /* forceSchedule = */ false); + + // Validate + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + ExtendedMockito.verify( + () -> AsyncRegistrationQueueJobService.schedule(any(), any()), never()); + verify(mMockJobScheduler, times(1)) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + @Test + public void scheduleIfNeeded_killSwitchOff_previouslyExecuted_forceSchedule_schedule() + throws Exception { + runWithMocks( + () -> { + // Setup + disableKillSwitch(); + + final Context mockContext = mock(Context.class); + doReturn(mMockJobScheduler) + .when(mockContext) + .getSystemService(JobScheduler.class); + final JobInfo mockJobInfo = mock(JobInfo.class); + doReturn(mockJobInfo) + .when(mMockJobScheduler) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + + // Execute + AsyncRegistrationQueueJobService.scheduleIfNeeded( + mockContext, /* forceSchedule = */ true); + + // Validate + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + ExtendedMockito.verify( + () -> AsyncRegistrationQueueJobService.schedule(any(), any()), + times(1)); + verify(mMockJobScheduler, times(1)) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + @Test + public void scheduleIfNeeded_killSwitchOff_previouslyNotExecuted_dontForceSchedule_schedule() + throws Exception { + runWithMocks( + () -> { + // Setup + disableKillSwitch(); + + final Context mockContext = mock(Context.class); + doReturn(mMockJobScheduler) + .when(mockContext) + .getSystemService(JobScheduler.class); + doReturn(/* noJobInfo = */ null) + .when(mMockJobScheduler) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + + // Execute + AsyncRegistrationQueueJobService.scheduleIfNeeded(mockContext, false); + + // Validate + // Allow background thread to execute + Thread.sleep(WAIT_IN_MILLIS); + ExtendedMockito.verify( + () -> AsyncRegistrationQueueJobService.schedule(any(), any()), + times(1)); + verify(mMockJobScheduler, times(1)) + .getPendingJob(eq(ASYNC_REGISTRATION_QUEUE_JOB_ID)); + }); + } + + private void runWithMocks(TestUtils.RunnableWithThrow execute) throws Exception { + MockitoSession session = + ExtendedMockito.mockitoSession() + .spyStatic(AsyncRegistrationQueueJobService.class) + .spyStatic(AdServicesLoggerImpl.class) + .spyStatic(DatastoreManagerFactory.class) + .spyStatic(EnrollmentDao.class) + .spyStatic(FlagsFactory.class) + .strictness(Strictness.LENIENT) + .startMocking(); + try { + // Setup mock everything in job + mMockDatastoreManager = mock(DatastoreManager.class); + doReturn(Optional.empty()) + .when(mMockDatastoreManager) + .runInTransactionWithResult(any()); + doNothing().when(mSpyService).jobFinished(any(), anyBoolean()); + doReturn(mMockJobScheduler).when(mSpyService).getSystemService(JobScheduler.class); + doReturn(Mockito.mock(Context.class)).when(mSpyService).getApplicationContext(); + ExtendedMockito.doReturn(mock(EnrollmentDao.class)) + .when(() -> EnrollmentDao.getInstance(any())); + ExtendedMockito.doReturn(mock(AdServicesLoggerImpl.class)) + .when(AdServicesLoggerImpl::getInstance); + ExtendedMockito.doNothing() + .when(() -> AsyncRegistrationQueueJobService.schedule(any(), any())); + ExtendedMockito.doReturn(mMockDatastoreManager) + .when(() -> DatastoreManagerFactory.getDatastoreManager(any())); + + // Execute + execute.run(); + } finally { + session.finishMocking(); + } + } + + private void enableKillSwitch() { + toggleKillSwitch(true); + } + + private void disableKillSwitch() { + toggleKillSwitch(false); + } + + private void toggleKillSwitch(boolean value) { + Flags mockFlags = Mockito.mock(Flags.class); + ExtendedMockito.doReturn(mockFlags).when(FlagsFactory::getFlags); + ExtendedMockito.doReturn(value).when(mockFlags).getRegistrationJobQueueKillSwitch(); + } +} |