chromium/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java

// Copyright 2017 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.components.background_task_scheduler.internal;

import android.app.job.JobInfo;
import android.os.PersistableBundle;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;
import org.chromium.components.background_task_scheduler.TaskInfo.NetworkType;

import java.util.concurrent.TimeUnit;

/** Tests for {@link BackgroundTaskSchedulerJobService}. */
@RunWith(BaseRobolectricTestRunner.class)
public class BackgroundTaskSchedulerJobServiceTest {
    private static final long CLOCK_TIME_MS = 1415926535000L;
    private static final long TIME_50_MIN_TO_MS = TimeUnit.MINUTES.toMillis(50);
    private static final long TIME_100_MIN_TO_MS = TimeUnit.MINUTES.toMillis(100);
    private static final long TIME_200_MIN_TO_MS = TimeUnit.MINUTES.toMillis(200);
    private static final long END_TIME_WITH_DEADLINE_MS =
            TIME_200_MIN_TO_MS + BackgroundTaskSchedulerJobService.DEADLINE_DELTA_MS;

    private BackgroundTaskSchedulerJobService.Clock mClock = () -> CLOCK_TIME_MS;

    @Before
    public void setUp() {
        BackgroundTaskSchedulerJobService.setClockForTesting(mClock);
    }

    @Test
    public void testOneOffTaskWithDeadline() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TIME_200_MIN_TO_MS).build();
        TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(oneOffTask.getTaskId(), jobInfo.getId());
        Assert.assertFalse(jobInfo.isPeriodic());
        Assert.assertEquals(TIME_200_MIN_TO_MS, jobInfo.getMaxExecutionDelayMillis());
    }

    @Test
    public void testOneOffTaskWithDeadlineAndExpiration() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create()
                        .setWindowEndTimeMs(TIME_200_MIN_TO_MS)
                        .setExpiresAfterWindowEndTime(true)
                        .build();
        TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(END_TIME_WITH_DEADLINE_MS, jobInfo.getMaxExecutionDelayMillis());
        Assert.assertEquals(
                CLOCK_TIME_MS,
                jobInfo.getExtras()
                        .getLong(
                                BackgroundTaskSchedulerDelegate.BACKGROUND_TASK_SCHEDULE_TIME_KEY));
        Assert.assertEquals(
                TIME_200_MIN_TO_MS,
                jobInfo.getExtras()
                        .getLong(BackgroundTaskSchedulerDelegate.BACKGROUND_TASK_END_TIME_KEY));
    }

    @Test
    public void testOneOffTaskWithWindow() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create()
                        .setWindowStartTimeMs(TIME_100_MIN_TO_MS)
                        .setWindowEndTimeMs(TIME_200_MIN_TO_MS)
                        .build();
        TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(oneOffTask.getTaskId(), jobInfo.getId());
        Assert.assertFalse(jobInfo.isPeriodic());
        Assert.assertEquals(TIME_100_MIN_TO_MS, jobInfo.getMinLatencyMillis());
        Assert.assertEquals(TIME_200_MIN_TO_MS, jobInfo.getMaxExecutionDelayMillis());
    }

    @Test
    public void testOneOffTaskWithWindowAndExpiration() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create()
                        .setWindowStartTimeMs(TIME_100_MIN_TO_MS)
                        .setWindowEndTimeMs(TIME_200_MIN_TO_MS)
                        .setExpiresAfterWindowEndTime(true)
                        .build();
        TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(
                oneOffTask.getOneOffInfo().getWindowStartTimeMs(), jobInfo.getMinLatencyMillis());
        Assert.assertEquals(END_TIME_WITH_DEADLINE_MS, jobInfo.getMaxExecutionDelayMillis());
        Assert.assertEquals(
                CLOCK_TIME_MS,
                jobInfo.getExtras()
                        .getLong(
                                BackgroundTaskSchedulerDelegate.BACKGROUND_TASK_SCHEDULE_TIME_KEY));
        Assert.assertEquals(
                TIME_200_MIN_TO_MS,
                jobInfo.getExtras()
                        .getLong(BackgroundTaskSchedulerDelegate.BACKGROUND_TASK_END_TIME_KEY));
    }

    @Test(expected = AssertionError.class)
    public void testUserInitiatedTaskWithEndTimeThrowsAssertionError() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create()
                        .setWindowStartTimeMs(TIME_100_MIN_TO_MS)
                        .setWindowEndTimeMs(TIME_200_MIN_TO_MS)
                        .build();
        TaskInfo.Builder builder = TaskInfo.createTask(TaskIds.TEST, timingInfo);
        builder.setUserInitiated(true);
        builder.setRequiredNetworkType(NetworkType.ANY);
        TaskInfo oneOffTask = builder.build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(oneOffTask.getTaskId(), jobInfo.getId());
        Assert.assertFalse(jobInfo.isPeriodic());
        Assert.assertEquals(NetworkType.ANY, jobInfo.getNetworkType());
        Assert.assertTrue(jobInfo.isUserInitiated());
        Assert.assertEquals(TIME_100_MIN_TO_MS, jobInfo.getMinLatencyMillis());
    }

    @Test
    @MinAndroidSdkLevel(34)
    public void testUserInitiatedTask() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create().setWindowStartTimeMs(TIME_100_MIN_TO_MS).build();
        TaskInfo.Builder builder = TaskInfo.createTask(TaskIds.TEST, timingInfo);
        builder.setUserInitiated(true);
        builder.setRequiredNetworkType(NetworkType.ANY);
        TaskInfo oneOffTask = builder.build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(oneOffTask.getTaskId(), jobInfo.getId());
        Assert.assertFalse(jobInfo.isPeriodic());
        Assert.assertEquals(NetworkType.ANY, jobInfo.getNetworkType());
        // Assert.assertTrue(jobInfo.isUserInitiated());
        Assert.assertEquals(TIME_100_MIN_TO_MS, jobInfo.getMinLatencyMillis());
    }

    @Test
    public void testPeriodicTaskWithoutFlex() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.PeriodicInfo.create().setIntervalMs(TIME_200_MIN_TO_MS).build();
        TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), periodicTask);
        Assert.assertEquals(periodicTask.getTaskId(), jobInfo.getId());
        Assert.assertTrue(jobInfo.isPeriodic());
        Assert.assertEquals(TIME_200_MIN_TO_MS, jobInfo.getIntervalMillis());
    }

    @Test
    public void testPeriodicTaskWithFlex() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.PeriodicInfo.create()
                        .setIntervalMs(TIME_200_MIN_TO_MS)
                        .setFlexMs(TIME_50_MIN_TO_MS)
                        .build();
        TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), periodicTask);
        Assert.assertEquals(TIME_200_MIN_TO_MS, jobInfo.getIntervalMillis());
        Assert.assertEquals(TIME_50_MIN_TO_MS, jobInfo.getFlexMillis());
    }

    @Test
    public void testTaskInfoWithExtras() {
        PersistableBundle taskExtras = new PersistableBundle();
        taskExtras.putString("foo", "bar");
        taskExtras.putBoolean("bools", true);
        taskExtras.putLong("longs", 1342543L);
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TIME_200_MIN_TO_MS).build();
        TaskInfo oneOffTask =
                TaskInfo.createTask(TaskIds.TEST, timingInfo).setExtras(taskExtras).build();
        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(), oneOffTask);
        Assert.assertEquals(oneOffTask.getTaskId(), jobInfo.getId());
        PersistableBundle jobExtras = jobInfo.getExtras();
        PersistableBundle persistableBundle =
                jobExtras.getPersistableBundle(
                        BackgroundTaskSchedulerJobService.BACKGROUND_TASK_EXTRAS_KEY);
        Assert.assertEquals(taskExtras.keySet().size(), persistableBundle.keySet().size());
        Assert.assertEquals(taskExtras.getString("foo"), persistableBundle.getString("foo"));
        Assert.assertEquals(taskExtras.getBoolean("bools"), persistableBundle.getBoolean("bools"));
        Assert.assertEquals(taskExtras.getLong("longs"), persistableBundle.getLong("longs"));
    }

    @Test
    public void testTaskInfoWithManyConstraints() {
        TaskInfo.TimingInfo timingInfo =
                TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TIME_200_MIN_TO_MS).build();
        TaskInfo.Builder taskBuilder = TaskInfo.createTask(TaskIds.TEST, timingInfo);

        JobInfo jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(),
                        taskBuilder.setIsPersisted(true).build());
        Assert.assertTrue(jobInfo.isPersisted());

        jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(),
                        taskBuilder.setRequiredNetworkType(TaskInfo.NetworkType.UNMETERED).build());
        Assert.assertEquals(JobInfo.NETWORK_TYPE_UNMETERED, jobInfo.getNetworkType());

        jobInfo =
                BackgroundTaskSchedulerJobService.createJobInfoFromTaskInfo(
                        RuntimeEnvironment.getApplication(),
                        taskBuilder.setRequiresCharging(true).build());
        Assert.assertTrue(jobInfo.isRequireCharging());
    }
}