blob: 40a5c26e03fe1e1647bd29622b23e777d96f2bd1 [file] [log] [blame]
/*
* 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.download;
import static com.android.adservices.download.MddJobService.KEY_MDD_TASK_TAG;
import static com.android.adservices.mockito.ExtendedMockitoExpectations.mockGetFlags;
import static com.android.adservices.mockito.MockitoExpectations.mockBackgroundJobsLoggingKillSwitch;
import static com.android.adservices.mockito.MockitoExpectations.verifyBackgroundJobsLogging;
import static com.android.adservices.mockito.MockitoExpectations.verifyBackgroundJobsSkipLogged;
import static com.android.adservices.mockito.MockitoExpectations.verifyJobFinishedLogged;
import static com.android.adservices.mockito.MockitoExpectations.verifyOnStopJobLogged;
import static com.android.adservices.spe.AdservicesJobInfo.MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB;
import static com.android.adservices.spe.AdservicesJobInfo.MDD_CHARGING_PERIODIC_TASK_JOB;
import static com.android.adservices.spe.AdservicesJobInfo.MDD_MAINTENANCE_PERIODIC_TASK_JOB;
import static com.android.adservices.spe.AdservicesJobInfo.MDD_WIFI_CHARGING_PERIODIC_TASK_JOB;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.android.libraries.mobiledatadownload.TaskScheduler.WIFI_CHARGING_PERIODIC_TASK;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.os.PersistableBundle;
import androidx.test.core.app.ApplicationProvider;
import com.android.adservices.common.JobServiceCallback;
import com.android.adservices.common.ProcessLifeguardRule;
import com.android.adservices.mockito.AdServicesExtendedMockitoRule;
import com.android.adservices.service.Flags;
import com.android.adservices.service.FlagsFactory;
import com.android.adservices.service.common.compat.ServiceCompatUtils;
import com.android.adservices.service.stats.Clock;
import com.android.adservices.service.stats.StatsdAdServicesLogger;
import com.android.adservices.spe.AdservicesJobServiceLogger;
import com.google.android.libraries.mobiledatadownload.MobileDataDownload;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Spy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/** Unit tests for {@link com.android.adservices.download.MddJobService} */
public class MddJobServiceTest {
private static final int JOB_SCHEDULED_WAIT_TIME_MS = 1_000;
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
private static final JobScheduler JOB_SCHEDULER = CONTEXT.getSystemService(JobScheduler.class);
private static final int MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID =
MDD_MAINTENANCE_PERIODIC_TASK_JOB.getJobId();
private static final int MDD_CHARGING_PERIODIC_TASK_JOB_ID =
MDD_CHARGING_PERIODIC_TASK_JOB.getJobId();
private static final int MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID =
MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB.getJobId();
private static final int MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID =
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB.getJobId();
private static final long TASK_PERIOD = 21_600L;
public static final int INTERVAL_MS = 10_000;
public static final int FLEX_MS = 1_000;
@Spy private MddJobService mSpyMddJobService;
@Mock JobParameters mMockJobParameters;
@Mock MobileDataDownload mMockMdd;
@Mock Flags mMockFlags;
@Mock MddFlags mMockMddFlags;
@Mock StatsdAdServicesLogger mMockStatsdLogger;
private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private AdservicesJobServiceLogger mLogger;
@Rule(order = 0)
public final AdServicesExtendedMockitoRule mAdServicesExtendedMockitoRule =
new AdServicesExtendedMockitoRule.Builder(this)
.spyStatic(MddJobService.class)
.spyStatic(MobileDataDownloadFactory.class)
.spyStatic(FlagsFactory.class)
.spyStatic(MddFlags.class)
.spyStatic(AdservicesJobServiceLogger.class)
.mockStatic(ServiceCompatUtils.class)
.build();
@Rule(order = 1)
public final ProcessLifeguardRule processLifeguard = new ProcessLifeguardRule();
@Before
public void setup() {
// Mock JobScheduler invocation in EpochJobService
assertThat(JOB_SCHEDULER).isNotNull();
assertNull(
"Job already scheduled before setup!",
JOB_SCHEDULER.getPendingJob(MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID));
mockGetFlags(mMockFlags);
doReturn(JOB_SCHEDULER).when(mSpyMddJobService).getSystemService(JobScheduler.class);
// Mock AdservicesJobServiceLogger to not actually log the stats to server
mLogger =
spy(new AdservicesJobServiceLogger(CONTEXT, Clock.SYSTEM_CLOCK, mMockStatsdLogger));
doNothing().when(mLogger).logExecutionStats(anyInt(), anyLong(), anyInt(), anyInt());
doReturn(mLogger).when(() -> AdservicesJobServiceLogger.getInstance(any(Context.class)));
// MDD Task Tag.
PersistableBundle bundle = new PersistableBundle();
bundle.putString(KEY_MDD_TASK_TAG, WIFI_CHARGING_PERIODIC_TASK);
when(mMockJobParameters.getExtras()).thenReturn(bundle);
}
@After
public void teardown() {
JOB_SCHEDULER.cancelAll();
}
@Test
public void testOnStartJob_killswitchIsOff_withoutLogging() throws Exception {
// Logging killswitch is on.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, true);
testOnStartJob_killswitchIsOff();
// Verify logging methods are not invoked.
verifyBackgroundJobsLogging(mLogger, never());
}
@Test
public void testOnStartJob_killswitchIsOff_withLogging() throws Exception {
// Logging killswitch is off.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, false);
testOnStartJob_killswitchIsOff();
// Verify logging methods are invoked.
verifyJobFinishedLogged(mLogger);
}
@Test
public void testOnStartJob_killswitchIsOn_withoutLogging() throws Exception {
// Logging killswitch is on.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, true);
testOnStartJob_killswitchIsOn();
// Verify logging methods are not invoked.
verifyBackgroundJobsLogging(mLogger, never());
}
@Test
public void testOnStartJob_killSwitchOn_withLogging() throws Exception {
// Logging killswitch is off.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, false);
testOnStartJob_killswitchIsOn();
// Verify logging methods are invoked.
verifyBackgroundJobsSkipLogged(mLogger);
}
@Test
public void testSchedule_killswitchOff() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
// Killswitch is off.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, false);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testSchedule_killswitchOn() throws Exception {
// Killswitch is off.
mockMddBackgroundTaskKillSwitch(/* toBeReturned */ true);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
verifyZeroInteractions(staticMockMarker(MobileDataDownloadFactory.class));
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ false,
/* checkPendingJob */ false);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testOnStopJob_withoutLogging() throws Exception {
// Logging killswitch is on.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, true);
testOnStopJob();
// Verify logging methods are not invoked.
verifyBackgroundJobsLogging(mLogger, never());
}
@Test
public void testOnStopJob_withLogging() throws Exception {
// Logging killswitch is off.
mockBackgroundJobsLoggingKillSwitch(mMockFlags, false);
testOnStopJob();
// Verify logging methods are invoked.
verifyOnStopJobLogged(mLogger);
}
@Test
public void testScheduleIfNeeded_Success() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeeded_ScheduledWithSameParameters() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.maintenanceGcmTaskPeriod()).thenReturn(TASK_PERIOD);
// The first invocation of scheduleIfNeeded() schedules the job.
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
// The second invocation of scheduleIfNeeded() with same parameters skips the scheduling.
callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ false,
/* checkPendingJob */ false);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeeded_ScheduledWithDifferentParameters() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.maintenanceGcmTaskPeriod()).thenReturn(TASK_PERIOD);
// The first invocation of scheduleIfNeeded() schedules the job.
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
when(mMockMddFlags.maintenanceGcmTaskPeriod()).thenReturn(TASK_PERIOD + 1L);
// The second invocation of scheduleIfNeeded() with different parameters should schedule a
// new job.
callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeeded_forceRun() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.maintenanceGcmTaskPeriod()).thenReturn(TASK_PERIOD);
// The first invocation of scheduleIfNeeded() schedules the job.
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
// The second invocation of scheduleIfNeeded() with same parameters skips the scheduling.
callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ false,
/* checkPendingJob */ false);
// The third invocation of scheduleIfNeeded() is forced and re-schedules the job.
callBack = scheduleJobInBackground(/* forceSchedule */ true);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
assertJobScheduled(
callBack,
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeededMddSingleTask_mddMaintenancePeriodicTask() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.maintenanceGcmTaskPeriod()).thenReturn(TASK_PERIOD);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeededMddSingleTask_mddChargingPeriodicTask() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.chargingGcmTaskPeriod()).thenReturn(TASK_PERIOD);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeededMddSingleTask_mddCellularChargingPeriodicTask()
throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.cellularChargingGcmTaskPeriod()).thenReturn(TASK_PERIOD);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testScheduleIfNeededMddSingleTask_mddWifiChargingPeriodicTask() throws Exception {
// Mock static method MddFlags.getInstance() to return Mock MddFlags.
mockGetMddFlags();
when(mMockMddFlags.wifiChargingGcmTaskPeriod()).thenReturn(TASK_PERIOD);
JobServiceCallback callBack = scheduleJobInBackground(/* forceSchedule */ false);
assertJobScheduled(
callBack,
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
/* shouldSchedule */ true,
/* checkPendingJob */ true);
waitForJobFinished(JOB_SCHEDULED_WAIT_TIME_MS);
}
@Test
public void testOnStartJob_shouldDisableJobTrue_withoutLogging() {
mockBackgroundJobsLoggingKillSwitch(mMockFlags, true);
testOnStartJob_shouldDisableJobTrue();
// Verify logging method is not invoked.
verifyBackgroundJobsLogging(mLogger, never());
}
@Test
public void testOnStartJob_shouldDisableJobTrue_withLoggingEnabled() {
mockBackgroundJobsLoggingKillSwitch(mMockFlags, false);
testOnStartJob_shouldDisableJobTrue();
// Verify no logging has happened even though logging is enabled because this field is not
// logged
verifyBackgroundJobsLogging(mLogger, never());
}
private void testOnStartJob_killswitchIsOn() throws InterruptedException {
// Killswitch is on.
mockMddBackgroundTaskKillSwitch(/* toBeReturned */ true);
doNothing().when(mSpyMddJobService).jobFinished(mMockJobParameters, false);
// Schedule the job to assert after starting that the scheduled job has been cancelled
JobInfo existingJobInfo =
new JobInfo.Builder(
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
new ComponentName(CONTEXT, MddJobService.class))
.setRequiresCharging(true)
.setPeriodic(INTERVAL_MS, FLEX_MS)
.build();
JOB_SCHEDULER.schedule(existingJobInfo);
assertThat(JOB_SCHEDULER.getPendingJob(MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID)).isNotNull();
JobServiceCallback callback = createJobFinishedCallback(mSpyMddJobService);
// Now verify that when the Job starts, it will unschedule itself.
assertThat(mSpyMddJobService.onStartJob(mMockJobParameters)).isFalse();
assertThat(JOB_SCHEDULER.getPendingJob(MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID)).isNull();
callback.assertJobFinished();
verify(mSpyMddJobService).jobFinished(mMockJobParameters, false);
verifyNoMoreInteractions(staticMockMarker(MobileDataDownloadFactory.class));
}
private void testOnStartJob_killswitchIsOff() throws InterruptedException {
// Killswitch is off.
mockMddBackgroundTaskKillSwitch(/* toBeReturned */ false);
doReturn(mMockMdd)
.when(() -> MobileDataDownloadFactory.getMdd(any(Context.class), any(Flags.class)));
JobServiceCallback callback = createJobFinishedCallback(mSpyMddJobService);
mSpyMddJobService.onStartJob(mMockJobParameters);
callback.assertJobFinished();
// Check that Mdd.handleTask is executed.
verify(() -> MobileDataDownloadFactory.getMdd(any(Context.class), any(Flags.class)));
verify(mMockMdd).handleTask(WIFI_CHARGING_PERIODIC_TASK);
}
private void testOnStopJob() throws InterruptedException {
JobServiceCallback callback = createOnStopJobCallback(mSpyMddJobService);
// Verify nothing throws
mSpyMddJobService.onStopJob(mMockJobParameters);
callback.assertJobFinished();
}
private void testOnStartJob_shouldDisableJobTrue() {
doReturn(true)
.when(
() ->
ServiceCompatUtils.shouldDisableExtServicesJobOnTPlus(
any(Context.class)));
doNothing().when(mSpyMddJobService).jobFinished(mMockJobParameters, false);
// Schedule the job to assert after starting that the scheduled job has been cancelled
JobInfo existingJobInfo =
new JobInfo.Builder(
MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID,
new ComponentName(CONTEXT, MddJobService.class))
.setRequiresCharging(true)
.setPeriodic(INTERVAL_MS, FLEX_MS)
.build();
JOB_SCHEDULER.schedule(existingJobInfo);
assertNotNull(JOB_SCHEDULER.getPendingJob(MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID));
// Now verify that when the Job starts, it will unschedule itself.
assertFalse(mSpyMddJobService.onStartJob(mMockJobParameters));
assertNull(JOB_SCHEDULER.getPendingJob(MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID));
verify(mSpyMddJobService).jobFinished(mMockJobParameters, false);
verifyNoMoreInteractions(staticMockMarker(MobileDataDownloadFactory.class));
}
// TODO(b/296945680): remove Thread.sleep().
/**
* Waits for current running job to finish before mocked {@code Flags} finished mocking.
*
* <p>Tests needs to call this at the end of the test if scheduled background job to prevent
* {@code android.permission.READ_DEVICE_CONFIG} permission error when scheduled job start
* running after mocked {@code flags} finished mocking.
*/
public void waitForJobFinished(int timeOutMs) throws InterruptedException {
Thread.sleep(timeOutMs);
}
private void mockGetMddFlags() {
doReturn(mMockMddFlags).when(MddFlags::getInstance);
}
private void mockMddBackgroundTaskKillSwitch(boolean toBeReturned) {
doReturn(toBeReturned).when(mMockFlags).getMddBackgroundTaskKillSwitch();
}
private JobServiceCallback createJobFinishedCallback(JobService jobService) {
JobServiceCallback callback = new JobServiceCallback();
doAnswer(
unusedInvocation -> {
callback.onJobFinished();
return null;
})
.when(jobService)
.jobFinished(any(), anyBoolean());
return callback;
}
private JobServiceCallback createOnStopJobCallback(JobService jobService) {
JobServiceCallback callback = new JobServiceCallback();
doAnswer(
invocation -> {
invocation.callRealMethod();
callback.onJobStopped();
return null;
})
.when(jobService)
.onStopJob(any());
return callback;
}
private JobServiceCallback scheduleJobInBackground(boolean forceSchedule) {
JobServiceCallback callback = new JobServiceCallback();
mExecutorService.execute(
() ->
callback.insertJobScheduledResult(
MddJobService.scheduleIfNeeded(CONTEXT, forceSchedule)));
return callback;
}
private void assertJobScheduled(
JobServiceCallback callback, int jobId, boolean shouldSchedule, boolean checkPendingJob)
throws InterruptedException {
assertWithMessage(
"Check callback received result. jobId: %s, shouldSchedule: %s",
jobId, shouldSchedule)
.that(callback.assertResultReceived())
.isEqualTo(shouldSchedule);
if (checkPendingJob) {
assertThat(JOB_SCHEDULER.getPendingJob(jobId)).isNotNull();
}
}
}