chromium/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskSchedulerTest.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.background_sync;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;

import org.chromium.base.ContextUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.background_sync.BackgroundSyncBackgroundTaskScheduler.BackgroundSyncTask;
import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory;
import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;

import java.util.concurrent.TimeUnit;

/** Unit tests for BackgroundSyncBackgroundTaskScheduler. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BackgroundSyncBackgroundTaskSchedulerTest {
    @Mock private BackgroundTaskScheduler mTaskScheduler;
    @Captor ArgumentCaptor<TaskInfo> mTaskInfo;

    private static final int ONE_DAY_IN_MILLISECONDS = (int) TimeUnit.DAYS.toMillis(1);
    private static final int ONE_WEEK_IN_MILLISECONDS = (int) TimeUnit.DAYS.toMillis(7);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler);
        ChromeBackgroundTaskFactory.setAsDefault();
        doReturn(true)
                .when(mTaskScheduler)
                .schedule(eq(ContextUtils.getApplicationContext()), mTaskInfo.capture());
    }

    private void verifyFixedTaskInfoValues(
            TaskInfo info, @BackgroundSyncBackgroundTaskScheduler.BackgroundSyncTask int taskType) {
        int taskId = BackgroundSyncBackgroundTaskScheduler.getAppropriateTaskId(taskType);

        assertEquals(taskId, info.getTaskId());
        assertTrue(info.isPersisted());
        assertFalse(info.isPeriodic());
        assertTrue(info.getOneOffInfo().expiresAfterWindowEndTime());
        assertEquals(TaskInfo.NetworkType.ANY, info.getRequiredNetworkType());

        long expectedSoonestDelayTime =
                info.getExtras()
                        .getLong(BackgroundSyncBackgroundTaskScheduler.SOONEST_EXPECTED_WAKETIME);
        assertTrue(expectedSoonestDelayTime > 0L);
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testScheduleOneOffTask() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        TaskInfo taskInfo = mTaskInfo.getValue();
        verifyFixedTaskInfoValues(
                taskInfo,
                BackgroundSyncBackgroundTaskScheduler.BackgroundSyncTask
                        .ONE_SHOT_SYNC_CHROME_WAKE_UP);

        assertEquals(ONE_DAY_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testSchedulePeriodicSyncWakeUpTask() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        TaskInfo taskInfo = mTaskInfo.getValue();
        verifyFixedTaskInfoValues(
                taskInfo,
                BackgroundSyncBackgroundTaskScheduler.BackgroundSyncTask
                        .PERIODIC_SYNC_CHROME_WAKE_UP);

        assertEquals(ONE_DAY_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testCancelOneShotTask() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        doNothing()
                .when(mTaskScheduler)
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID));

        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .cancelOneOffTask(BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP);
        verify(mTaskScheduler, times(1))
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID));
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testCancelPeriodicSyncWakeUpTask() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        doNothing()
                .when(mTaskScheduler)
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID));

        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .cancelOneOffTask(BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP);
        verify(mTaskScheduler, times(1))
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID));
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testScheduleOneOffTaskCalledTwice() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        TaskInfo taskInfo = mTaskInfo.getValue();
        assertEquals(ONE_DAY_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());

        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_WEEK_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        taskInfo = mTaskInfo.getValue();
        assertEquals(ONE_WEEK_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testSchedulePeriodicSyncTaskTwice() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        TaskInfo taskInfo = mTaskInfo.getValue();
        assertEquals(ONE_DAY_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());

        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_WEEK_IN_MILLISECONDS);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));

        taskInfo = mTaskInfo.getValue();
        assertEquals(ONE_WEEK_IN_MILLISECONDS, taskInfo.getOneOffInfo().getWindowStartTimeMs());
    }

    @Test
    @Feature({"BackgroundSync"})
    public void testScheduleOneShotSyncWakeUpThenCancel() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .cancelOneOffTask(BackgroundSyncTask.ONE_SHOT_SYNC_CHROME_WAKE_UP);

        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));
        verify(mTaskScheduler, times(1))
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID));
    }

    @Test
    @Feature({"BackgroundSync"})
    public void schedulePeriodicSyncWakeUpTaskThenCancel() {
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .scheduleOneOffTask(
                        BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP,
                        /* minDelayMs= */ ONE_DAY_IN_MILLISECONDS);
        BackgroundSyncBackgroundTaskScheduler.getInstance()
                .cancelOneOffTask(BackgroundSyncTask.PERIODIC_SYNC_CHROME_WAKE_UP);
        verify(mTaskScheduler, times(1))
                .schedule(eq(ContextUtils.getApplicationContext()), eq(mTaskInfo.getValue()));
        verify(mTaskScheduler, times(1))
                .cancel(
                        eq(ContextUtils.getApplicationContext()),
                        eq(TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID));
    }
}