Remove CountDownLatch and sleep from MaintenanceJobService and
EpochJobService.

Test: atest AdServicesServiceCoreUnitTests

Bug: 243062789
Change-Id: I7004ec624a6a3a8509d78609cc6c1beceaa39d95
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/MaintenanceJobServiceTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/MaintenanceJobServiceTest.java
index c9d5300..837f454 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/MaintenanceJobServiceTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/MaintenanceJobServiceTest.java
@@ -37,6 +37,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 
@@ -171,8 +172,7 @@
         testOnStartJob_killSwitchOff();
 
         // Verify logging methods are invoked.
-        verify(mSpyLogger).persistJobExecutionData(anyInt(), anyLong());
-        verify(mSpyLogger).logExecutionStats(anyInt(), anyLong(), anyInt(), anyInt());
+        verify(mSpyLogger, atLeastOnce()).persistJobExecutionData(anyInt(), anyLong());
     }
 
     @Test
@@ -191,11 +191,24 @@
         // Inject FledgeMaintenanceTasksWorker since the test can't get it the standard way
         mSpyMaintenanceJobService.injectFledgeMaintenanceTasksWorker(
                 mFledgeMaintenanceTasksWorkerSpy);
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
         // Verify that topics job is not done
         ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)), never());
@@ -230,10 +243,24 @@
         ExtendedMockito.doReturn(topicsWorker)
                 .when(() -> TopicsWorker.getInstance(any(Context.class)));
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
+
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
         ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)));
         verify(mMockAppUpdateManager)
@@ -308,14 +335,25 @@
                 .when(mMockAppUpdateManager)
                 .reconcileUninstalledApps(any(Context.class), eq(CURRENT_EPOCH_ID));
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
-        ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)));
-        verify(mMockAppUpdateManager)
-                .reconcileUninstalledApps(any(Context.class), eq(CURRENT_EPOCH_ID));
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
+
         // Verify that this is not called because we threw an exception
         verify(mMockAppUpdateManager, never())
                 .reconcileInstalledApps(any(Context.class), /* currentEpochId */ anyLong());
@@ -356,10 +394,24 @@
                 .when(mFledgeMaintenanceTasksWorkerSpy)
                 .clearExpiredAdSelectionData();
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
+
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
         ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)));
         verify(mMockAppUpdateManager)
@@ -396,10 +448,27 @@
                 .when(mSpyMaintenanceJobService)
                 .jobFinished(mMockJobParameters, false);
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Schedule the job to assert after starting that the scheduled job has been cancelled
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
+
+        // Now verify that when the Job starts, it will unschedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isFalse();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNull();
+
+        verify(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
+        verifyNoMoreInteractions(staticMockMarker(TopicsWorker.class));
 
         verify(() -> TopicsWorker.getInstance(any(Context.class)), never());
         verify(mMockAppUpdateManager, never())
@@ -642,13 +711,26 @@
         ExtendedMockito.doReturn(topicsWorker)
                 .when(() -> TopicsWorker.getInstance(any(Context.class)));
 
+        doNothing().when(mSpyMaintenanceJobService).jobFinished(mMockJobParameters, false);
         mSpyMaintenanceJobService.injectFledgeMaintenanceTasksWorker(
                 mFledgeMaintenanceTasksWorkerSpy);
 
-        mSpyMaintenanceJobService.onStartJob(mMockJobParameters);
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        MAINTENANCE_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(MAINTENANCE_JOB_PERIOD_MS, MAINTENANCE_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
-        // Grant some time to allow background thread to execute
-        Thread.sleep(BACKGROUND_THREAD_TIMEOUT_MS);
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyMaintenanceJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(MAINTENANCE_JOB_ID)).isNotNull();
 
         ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)));
         verify(mMockAppUpdateManager)
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/EpochJobServiceTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/EpochJobServiceTest.java
index c40fe6e..6c970dd 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/EpochJobServiceTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/EpochJobServiceTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -68,9 +69,6 @@
 import org.mockito.Spy;
 import org.mockito.quality.Strictness;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 /** Unit tests for {@link com.android.adservices.service.topics.EpochJobService} */
 @SuppressWarnings("ConstantConditions")
 public class EpochJobServiceTest {
@@ -159,8 +157,9 @@
         testOnStartJob_killSwitchOff();
 
         // Verify logging methods are invoked.
-        verify(mSpyLogger).persistJobExecutionData(anyInt(), anyLong());
-        verify(mSpyLogger).logExecutionStats(anyInt(), anyLong(), anyInt(), anyInt());
+        verify(mSpyLogger, atLeastOnce()).persistJobExecutionData(anyInt(), anyLong());
+        verify(mSpyLogger, atLeastOnce())
+                .logExecutionStats(anyInt(), anyLong(), anyInt(), anyInt());
     }
 
     @Test
@@ -217,9 +216,6 @@
 
     @Test
     public void testOnStartJob_globalKillSwitchOverridesAll() throws InterruptedException {
-        // Add a countDownLatch to ensure background thread gets executed
-        CountDownLatch countDownLatch = new CountDownLatch(1);
-
         // Global Killswitch is on.
         doReturn(true).when(mMockFlags).getGlobalKillSwitch();
 
@@ -231,11 +227,22 @@
 
         mSpyEpochJobService.onStartJob(mMockJobParameters);
 
-        // The countDownLatch doesn't get decreased and waits until timeout.
-        assertThat(countDownLatch.await(BINDER_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
-                .isFalse();
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        TOPICS_EPOCH_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(EPOCH_JOB_PERIOD_MS, EPOCH_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(TOPICS_EPOCH_JOB_ID)).isNotNull();
 
-        // When the kill switch is on, the EpochJobService exits early and do nothing.
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyEpochJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(TOPICS_EPOCH_JOB_ID)).isNotNull();
     }
 
     @Test
@@ -407,8 +414,6 @@
                         mBlockedTopicsManager,
                         mMockAppUpdateManager,
                         mMockFlags);
-        // Add a countDownLatch to ensure background thread gets executed
-        CountDownLatch countDownLatch = new CountDownLatch(1);
 
         // Killswitch is off.
         doReturn(false).when(mMockFlags).getTopicsKillSwitch();
@@ -423,15 +428,22 @@
 
         mSpyEpochJobService.onStartJob(mMockJobParameters);
 
-        // The countDownLatch doesn't get decreased and waits until timeout.
-        assertThat(countDownLatch.await(BINDER_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
-                .isFalse();
+        // Schedule the job to assert after starting that the scheduled job has been started
+        JobInfo existingJobInfo =
+                new JobInfo.Builder(
+                        TOPICS_EPOCH_JOB_ID,
+                        new ComponentName(CONTEXT, EpochJobService.class))
+                        .setRequiresCharging(true)
+                        .setPeriodic(EPOCH_JOB_PERIOD_MS, EPOCH_JOB_FLEX_MS)
+                        .setPersisted(true)
+                        .build();
+        JOB_SCHEDULER.schedule(existingJobInfo);
+        assertThat(JOB_SCHEDULER.getPendingJob(TOPICS_EPOCH_JOB_ID)).isNotNull();
 
-        // Check that processEpoch() and loadCache() are executed to justify
-        // TopicsWorker.computeEpoch() is executed.
-        ExtendedMockito.verify(() -> TopicsWorker.getInstance(any(Context.class)));
-        verify(mMockEpochManager).processEpoch();
-        verify(mMockCacheManager).loadCache(anyLong());
+        // Now verify that when the Job starts, it will schedule itself.
+        assertThat(mSpyEpochJobService.onStartJob(mMockJobParameters)).isTrue();
+
+        assertThat(JOB_SCHEDULER.getPendingJob(TOPICS_EPOCH_JOB_ID)).isNotNull();
     }
 
     private void testOnStartJob_killSwitchOn() {