101ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamspackage com.android.server.job;
23d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
33d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
43d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.content.ComponentName;
53d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.content.Context;
67060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo;
77060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo.Builder;
83d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.os.PersistableBundle;
9fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williamsimport android.os.SystemClock;
103d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.test.AndroidTestCase;
113d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.test.RenamingDelegatingContext;
123d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.util.Log;
1301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamsimport android.util.ArraySet;
143d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
152f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tateimport com.android.server.job.JobStore.JobSet;
167060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport com.android.server.job.controllers.JobStatus;
173d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamsimport java.util.Iterator;
193d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
203d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams/**
213d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * Test reading and writing correctly from file.
223d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams */
2301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamspublic class JobStoreTest extends AndroidTestCase {
243d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private static final String TAG = "TaskStoreTest";
253d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private static final String TEST_PREFIX = "_test_";
2601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams
273d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private static final int SOME_UID = 34234;
283d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private ComponentName mComponent;
2901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams    private static final long IO_WAIT = 1000L;
303d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
317060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate    JobStore mTaskStoreUnderTest;
323d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    Context mTestContext;
333d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
343d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    @Override
353d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    public void setUp() throws Exception {
363d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
373d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
3801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        mTaskStoreUnderTest =
3901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir());
403d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
413d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
423d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
433d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    @Override
443d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    public void tearDown() throws Exception {
453d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTaskStoreUnderTest.clear();
463d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
473d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
483d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    public void testMaybeWriteStatusToDisk() throws Exception {
493d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        int taskId = 5;
503d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        long runByMillis = 20000L; // 20s
513d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        long runFromMillis = 2000L; // 2s
523d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        long initialBackoff = 10000L; // 10s
533d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
547060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate        final JobInfo task = new Builder(taskId, mComponent)
553d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setRequiresCharging(true)
56d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
57d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setBackoffCriteria(initialBackoff, JobInfo.BACKOFF_POLICY_EXPONENTIAL)
583d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setOverrideDeadline(runByMillis)
593d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setMinimumLatency(runFromMillis)
60d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setPersisted(true)
613d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .build();
621085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
633d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTaskStoreUnderTest.add(ts);
643d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        Thread.sleep(IO_WAIT);
653d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        // Manually load tasks from xml file.
662f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
6701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
6801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams
6901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size());
702f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0);
7101ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertTasksEqual(task, loadedTaskStatus.getJob());
7248a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts));
7301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
7401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
7501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
7601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
7701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed());
783d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
793d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
803d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
813d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    public void testWritingTwoFilesToDisk() throws Exception {
827060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate        final JobInfo task1 = new Builder(8, mComponent)
833d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setRequiresDeviceIdle(true)
843d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setPeriodic(10000L)
853d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setRequiresCharging(true)
86d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setPersisted(true)
873d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .build();
887060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate        final JobInfo task2 = new Builder(12, mComponent)
893d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setMinimumLatency(5000L)
90d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR)
913d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setOverrideDeadline(30000L)
92d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
93d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setPersisted(true)
943d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .build();
951085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null);
961085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
973d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTaskStoreUnderTest.add(taskStatus1);
983d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTaskStoreUnderTest.add(taskStatus2);
993d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        Thread.sleep(IO_WAIT);
10001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams
1012f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
10201ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
10301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
1042f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator();
10501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        JobStatus loaded1 = it.next();
10601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        JobStatus loaded2 = it.next();
107fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
108fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        // Reverse them so we know which comparison to make.
109fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        if (loaded1.getJobId() != 8) {
110fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams            JobStatus tmp = loaded1;
111fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams            loaded1 = loaded2;
112fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams            loaded2 = tmp;
113fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        }
114fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
11501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertTasksEqual(task1, loaded1.getJob());
11601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertTasksEqual(task2, loaded2.getJob());
11748a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus1));
11848a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus2));
11901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        // Check that the loaded task has the correct runtimes.
12001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
12101ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime());
12201ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
12301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed());
12401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
12501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime());
12601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
12701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams                taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed());
1283d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1293d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
1303d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1313d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    public void testWritingTaskWithExtras() throws Exception {
1327060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate        JobInfo.Builder b = new Builder(8, mComponent)
1333d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setRequiresDeviceIdle(true)
1343d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                .setPeriodic(10000L)
135900c67fc51fc2672458dd1c9641250f2ecc01a31Matthew Williams                .setRequiresCharging(true)
136d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                .setPersisted(true);
1373d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1383d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        PersistableBundle extras = new PersistableBundle();
1393d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        extras.putDouble("hello", 3.2);
1403d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        extras.putString("hi", "there");
1413d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        extras.putInt("into", 3);
1423d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        b.setExtras(extras);
1437060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate        final JobInfo task = b.build();
1441085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
1453d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1463d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        mTaskStoreUnderTest.add(taskStatus);
1473d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        Thread.sleep(IO_WAIT);
1483d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
1492f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
15001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
15101ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
1522f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
15301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams        assertTasksEqual(task, loaded.getJob());
1543d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
1558e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge    public void testWritingTaskWithSourcePackage() throws Exception {
1568e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        JobInfo.Builder b = new Builder(8, mComponent)
1578e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setRequiresDeviceIdle(true)
1588e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setPeriodic(10000L)
1598e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setRequiresCharging(true)
1608e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setPersisted(true);
161b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
1621085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn                "com.google.android.gms", 0, null);
1638e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge
1648e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        mTaskStoreUnderTest.add(taskStatus);
1658e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        Thread.sleep(IO_WAIT);
1668e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge
1672f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
1688e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
1698e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
1702f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
1718e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Source package not equal.", loaded.getSourcePackageName(),
1728e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                taskStatus.getSourcePackageName());
1738e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Source user not equal.", loaded.getSourceUserId(),
1748e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                taskStatus.getSourceUserId());
1758e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge    }
1768e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge
1778e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge    public void testWritingTaskWithFlex() throws Exception {
1788e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        JobInfo.Builder b = new Builder(8, mComponent)
1798e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setRequiresDeviceIdle(true)
1808e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setPeriodic(5*60*60*1000, 1*60*60*1000)
1818e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setRequiresCharging(true)
1828e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setPersisted(true);
1831085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
1848e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge
1858e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        mTaskStoreUnderTest.add(taskStatus);
1868e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        Thread.sleep(IO_WAIT);
1878e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge
1882f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
1898e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
1908e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
1912f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
1928e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
1938e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                taskStatus.getJob().getIntervalMillis());
1948e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
1958e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                taskStatus.getJob().getFlexMillis());
1968e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge    }
1973d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
198fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams    public void testMassivePeriodClampedOnRead() throws Exception {
1998e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        final long ONE_HOUR = 60*60*1000L; // flex
2008e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        final long TWO_HOURS = 2 * ONE_HOUR; // period
201fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        JobInfo.Builder b = new Builder(8, mComponent)
2028e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                .setPeriodic(TWO_HOURS, ONE_HOUR)
203fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams                .setPersisted(true);
204fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        final long invalidLateRuntimeElapsedMillis =
2058e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS;  // > period+flex
206fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        final long invalidEarlyRuntimeElapsedMillis =
2078e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
208b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn        final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
2091085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn                0 /* sourceUserId */, "someTag",
210fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
211fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
212fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        mTaskStoreUnderTest.add(js);
213fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        Thread.sleep(IO_WAIT);
214fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
2152f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
216fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
217fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
2182f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
219fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
220fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        // Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll
221fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        // call SystemClock.elapsedRealtime after doing the disk i/o.
222fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        final long newNowElapsed = SystemClock.elapsedRealtime();
223fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        assertTrue("Early runtime wasn't correctly clamped.",
2248e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS);
2258e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge        // Assert late runtime was clamped to be now + period + flex.
226fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams        assertTrue("Early runtime wasn't correctly clamped.",
2278e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
2285db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge    }
2295db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge
2305db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge    public void testPriorityPersisted() throws Exception {
2315db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge        JobInfo.Builder b = new Builder(92, mComponent)
2325db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge                .setOverrideDeadline(5000)
2335db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge                .setPriority(42)
2345db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge                .setPersisted(true);
2351085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
2365db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge        mTaskStoreUnderTest.add(js);
2375db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge        Thread.sleep(IO_WAIT);
2382f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
2395db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
2402f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
2415db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge        assertEquals("Priority not correctly persisted.", 42, loaded.getPriority());
242fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams    }
243fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams
2443d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    /**
2457ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge     * Test that non persisted job is not written to disk.
2467ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge     */
2477ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge    public void testNonPersistedTaskIsNotPersisted() throws Exception {
2487ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        JobInfo.Builder b = new Builder(42, mComponent)
2497ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge                .setOverrideDeadline(10000)
2507ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge                .setPersisted(false);
2511085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
2527ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        mTaskStoreUnderTest.add(jsNonPersisted);
2537ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        b = new Builder(43, mComponent)
2547ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge                .setOverrideDeadline(10000)
2557ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge                .setPersisted(true);
2561085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
2577ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        mTaskStoreUnderTest.add(jsPersisted);
2587ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        Thread.sleep(IO_WAIT);
2592f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        final JobSet jobStatusSet = new JobSet();
2607ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
2617ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        assertEquals("Job count is incorrect.", 1, jobStatusSet.size());
2622f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate        JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next();
2637ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge        assertEquals("Wrong job persisted.", 43, jobStatus.getJobId());
2647ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge    }
2657ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge
2667ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge    /**
2673d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     * Helper function to throw an error if the provided task and TaskStatus objects are not equal.
2683d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     */
2697060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate    private void assertTasksEqual(JobInfo first, JobInfo second) {
2703d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different task ids.", first.getId(), second.getId());
2713d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different components.", first.getService(), second.getService());
2723d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic());
2733d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different period.", first.getIntervalMillis(), second.getIntervalMillis());
2743d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different inital backoff.", first.getInitialBackoffMillis(),
2753d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.getInitialBackoffMillis());
2763d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Different backoff policy.", first.getBackoffPolicy(),
2773d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.getBackoffPolicy());
2783d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
2793d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid charging constraint.", first.isRequireCharging(),
2803d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.isRequireCharging());
2813d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
2823d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.isRequireDeviceIdle());
2833d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid unmetered constraint.",
284d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                first.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED,
285d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                second.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED);
2863d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid connectivity constraint.",
287d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                first.getNetworkType() == JobInfo.NETWORK_TYPE_ANY,
288d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams                second.getNetworkType() == JobInfo.NETWORK_TYPE_ANY);
2893d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid deadline constraint.",
2903d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                first.hasLateConstraint(),
2913d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.hasLateConstraint());
2923d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Invalid delay constraint.",
2933d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                first.hasEarlyConstraint(),
2943d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                second.hasEarlyConstraint());
2953d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertEquals("Extras don't match",
2963d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams                first.getExtras().toString(), second.getExtras().toString());
2973d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
2983d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
2993d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    /**
3003d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     * When comparing timestamps before and after DB read/writes (to make sure we're saving/loading
3013d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     * the correct values), there is some latency involved that terrorises a naive assertEquals().
3023d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     * We define a <code>DELTA_MILLIS</code> as a function variable here to make this comparision
3033d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     * more reasonable.
3043d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams     */
3053d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private void compareTimestampsSubjectToIoLatency(String error, long ts1, long ts2) {
3063d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        final long DELTA_MILLIS = 700L;  // We allow up to 700ms of latency for IO read/writes.
3073d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams        assertTrue(error, Math.abs(ts1 - ts2) < DELTA_MILLIS + IO_WAIT);
3083d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    }
3093d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
3103d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams    private static class StubClass {}
3113d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams
31201ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams}
313