Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.jobscheduler.cts;
     18 
     19 import android.annotation.TargetApi;
     20 import android.app.job.JobInfo;
     21 import android.app.job.JobWorkItem;
     22 import android.content.ContentProviderClient;
     23 import android.content.Intent;
     24 import android.jobscheduler.MockJobService.TestWorkItem;
     25 import android.net.Uri;
     26 
     27 import com.android.compatibility.common.util.SystemUtil;
     28 
     29 import java.util.ArrayList;
     30 
     31 /**
     32  * Schedules jobs with the {@link android.app.job.JobScheduler} by enqueue work in to
     33  * them and processing it.
     34  */
     35 @TargetApi(26)
     36 public class EnqueueJobWorkTest extends ConstraintTest {
     37     private static final String TAG = "ClipDataJobTest";
     38 
     39     /** Unique identifier for the job scheduled by this suite of tests. */
     40     public static final int ENQUEUE_WORK_JOB_ID = EnqueueJobWorkTest.class.hashCode();
     41 
     42     private JobInfo.Builder mBuilder;
     43     private ContentProviderClient mProvider;
     44 
     45     @Override
     46     public void setUp() throws Exception {
     47         super.setUp();
     48 
     49         mBuilder = new JobInfo.Builder(ENQUEUE_WORK_JOB_ID, kJobServiceComponent);
     50         mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
     51     }
     52 
     53     @Override
     54     public void tearDown() throws Exception {
     55         super.tearDown();
     56         mProvider.close();
     57         mJobScheduler.cancel(ENQUEUE_WORK_JOB_ID);
     58     }
     59 
     60     private boolean intentEquals(Intent i1, Intent i2) {
     61         if (i1 == i2) {
     62             return true;
     63         }
     64         if (i1 == null || i2 == null) {
     65             return false;
     66         }
     67         return i1.filterEquals(i2);
     68     }
     69 
     70     private void compareWork(TestWorkItem[] expected, ArrayList<JobWorkItem> received) {
     71         if (received == null) {
     72             fail("Didn't receive any expected work.");
     73         }
     74         ArrayList<TestWorkItem> expectedArray = new ArrayList<>();
     75         for (int i = 0; i < expected.length; i++) {
     76             expectedArray.add(expected[i]);
     77         }
     78         for (int i = 0; i < received.size(); i++) {
     79             JobWorkItem work = received.get(i);
     80             if (i < expected.length && expected[i].subitems != null) {
     81                 TestWorkItem[] sub = expected[i].subitems;
     82                 for (int j = 0; j < sub.length; j++) {
     83                     expectedArray.add(sub[j]);
     84                 }
     85             }
     86             if (i >= expectedArray.size()) {
     87                 fail("Received more than " + expected.length + " work items, first extra is "
     88                         + work);
     89             }
     90             if (!intentEquals(work.getIntent(), expectedArray.get(i).intent)) {
     91                 fail("Received work #" + i + " " + work.getIntent() + " but expected " + expected[i]);
     92             }
     93             if (work.getDeliveryCount() != expectedArray.get(i).deliveryCount) {
     94                 fail("Received work #" + i + " " + work.getIntent() + " delivery count is "
     95                         + work.getDeliveryCount() + " but expected "
     96                         + expectedArray.get(i).deliveryCount);
     97             }
     98         }
     99         if (received.size() < expected.length) {
    100             fail("Received only " + received.size() + " work items, but expected "
    101                             + expected.length);
    102         }
    103     }
    104 
    105     /**
    106      * Test basic enqueueing of work.
    107      */
    108     public void testEnqueueOneWork() throws Exception {
    109         Intent work1 = new Intent("work1");
    110         TestWorkItem[] work = new TestWorkItem[] { new TestWorkItem(work1) };
    111         kTestEnvironment.setExpectedExecutions(1);
    112         kTestEnvironment.setExpectedWork(work);
    113         mJobScheduler.enqueue(mBuilder.setOverrideDeadline(0).build(), new JobWorkItem(work1));
    114         kTestEnvironment.readyToWork();
    115         assertTrue("Job with work enqueued did not fire.",
    116                 kTestEnvironment.awaitExecution());
    117         compareWork(work, kTestEnvironment.getLastReceivedWork());
    118         if (kTestEnvironment.getLastErrorMessage() != null) {
    119             fail(kTestEnvironment.getLastErrorMessage());
    120         }
    121     }
    122 
    123     /**
    124      * Test basic enqueueing batches of work.
    125      */
    126     public void testEnqueueMultipleWork() throws Exception {
    127         Intent work1 = new Intent("work1");
    128         Intent work2 = new Intent("work2");
    129         Intent work3 = new Intent("work3");
    130         Intent work4 = new Intent("work4");
    131         Intent work5 = new Intent("work5");
    132         Intent work6 = new Intent("work6");
    133         Intent work7 = new Intent("work7");
    134         Intent work8 = new Intent("work8");
    135         TestWorkItem[] work = new TestWorkItem[] {
    136                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    137                 new TestWorkItem(work4), new TestWorkItem(work5), new TestWorkItem(work6),
    138                 new TestWorkItem(work7), new TestWorkItem(work8) };
    139         kTestEnvironment.setExpectedExecutions(1);
    140         kTestEnvironment.setExpectedWork(work);
    141         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    142         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    143         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    144         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    145         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    146         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    147         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    148         mJobScheduler.enqueue(ji, new JobWorkItem(work7));
    149         mJobScheduler.enqueue(ji, new JobWorkItem(work8));
    150         kTestEnvironment.readyToWork();
    151         assertTrue("Job with work enqueued did not fire.",
    152                 kTestEnvironment.awaitExecution());
    153         compareWork(work, kTestEnvironment.getLastReceivedWork());
    154     }
    155 
    156     /**
    157      * Test basic enqueueing batches of work, with new work coming in while processing existing
    158      * work.
    159      */
    160     public void testEnqueueMultipleSubWork() throws Exception {
    161         Intent work1 = new Intent("work1");
    162         Intent work2 = new Intent("work2");
    163         Intent work3 = new Intent("work3");
    164         Intent work4 = new Intent("work4");
    165         Intent work5 = new Intent("work5");
    166         Intent work6 = new Intent("work6");
    167         Intent work7 = new Intent("work7");
    168         Intent work8 = new Intent("work8");
    169         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    170         TestWorkItem[] work = new TestWorkItem[]{
    171                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    172                 new TestWorkItem(work4, ji, new TestWorkItem[] {
    173                         new TestWorkItem(work5), new TestWorkItem(work6),
    174                         new TestWorkItem(work7), new TestWorkItem(work8)})
    175         };
    176         kTestEnvironment.setExpectedExecutions(1);
    177         kTestEnvironment.setExpectedWork(work);
    178         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    179         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    180         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    181         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    182         kTestEnvironment.readyToWork();
    183         assertTrue("Job with work enqueued did not fire.",
    184                 kTestEnvironment.awaitExecution());
    185         compareWork(work, kTestEnvironment.getLastReceivedWork());
    186     }
    187 
    188     /**
    189      * Test job getting stopped while processing work and that work being redelivered.
    190      */
    191     public void testEnqueueMultipleRedeliver() throws Exception {
    192         Intent work1 = new Intent("work1");
    193         Intent work2 = new Intent("work2");
    194         Intent work3 = new Intent("work3");
    195         Intent work4 = new Intent("work4");
    196         Intent work5 = new Intent("work5");
    197         Intent work6 = new Intent("work6");
    198         TestWorkItem[] initialWork = new TestWorkItem[] {
    199                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    200                 new TestWorkItem(work4, TestWorkItem.FLAG_WAIT_FOR_STOP, 1) };
    201         kTestEnvironment.setExpectedExecutions(1);
    202         kTestEnvironment.setExpectedWaitForStop();
    203         kTestEnvironment.setExpectedWork(initialWork);
    204         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    205         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    206         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    207         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    208         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    209         kTestEnvironment.readyToWork();
    210 
    211         // Now wait for the job to get to the point where it is processing the last
    212         // work and waiting for it to be stopped.
    213         assertTrue("Job with work enqueued did not wait to stop.",
    214                 kTestEnvironment.awaitWaitingForStop());
    215 
    216         // Cause the job to timeout (stop) immediately, and wait for its execution to finish.
    217         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler timeout "
    218                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    219         assertTrue("Job with work enqueued did not finish.",
    220                 kTestEnvironment.awaitExecution());
    221         compareWork(initialWork, kTestEnvironment.getLastReceivedWork());
    222 
    223         // Now we are going to add some more work, restart the job, and see if it correctly
    224         // redelivers the last work and delivers the new work.
    225         TestWorkItem[] finalWork = new TestWorkItem[] {
    226                 new TestWorkItem(work4, 0, 2), new TestWorkItem(work5), new TestWorkItem(work6) };
    227         kTestEnvironment.setExpectedExecutions(1);
    228         kTestEnvironment.setExpectedWork(finalWork);
    229         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    230         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    231         kTestEnvironment.readyToWork();
    232         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler run "
    233                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    234 
    235         assertTrue("Restarted with work enqueued did not execute.",
    236                 kTestEnvironment.awaitExecution());
    237         compareWork(finalWork, kTestEnvironment.getLastReceivedWork());
    238     }
    239 
    240     /**
    241      * Test basic enqueueing batches of work.
    242      */
    243     public void testEnqueueMultipleUriGrantWork() throws Exception {
    244         // Start out with storage low, so job is enqueued but not executed yet.
    245         setStorageState(true);
    246 
    247         // We need to get a permission grant so that we can grant it to ourself.
    248         mProvider.call("grant", MY_PACKAGE, mFirstUriBundle);
    249         mProvider.call("grant", MY_PACKAGE, mSecondUriBundle);
    250         assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    251                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    252         assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    253                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    254 
    255         Intent work1 = new Intent("work1");
    256         work1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    257                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    258         work1.setData(mFirstUri);
    259         work1.setClipData(mSecondClipData);
    260 
    261         Intent work2 = new Intent("work2");
    262         work2.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    263                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    264         work2.setData(mFirstUri);
    265 
    266         TestWorkItem[] work = new TestWorkItem[] {
    267                 new TestWorkItem(work1, new Uri[] { mFirstUri, mSecondUri}, new Uri[0]),
    268                 new TestWorkItem(work2, new Uri[] { mFirstUri }, new Uri[] { mSecondUri}) };
    269         kTestEnvironment.setExpectedExecutions(1);
    270         kTestEnvironment.setExpectedWork(work);
    271         JobInfo ji = mBuilder.setOverrideDeadline(0).setRequiresStorageNotLow(true).build();
    272         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    273         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    274 
    275         // Remove the explicit grant, we should still have a grant due to the job.
    276         mProvider.call("revoke", MY_PACKAGE, mFirstUriBundle);
    277         mProvider.call("revoke", MY_PACKAGE, mSecondUriBundle);
    278         assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    279                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    280         assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    281                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    282 
    283         kTestEnvironment.readyToWork();
    284 
    285         // Now allow the job to run.
    286         setStorageState(false);
    287 
    288         assertTrue("Job with work enqueued did not fire.",
    289                 kTestEnvironment.awaitExecution());
    290         compareWork(work, kTestEnvironment.getLastReceivedWork());
    291 
    292         // And wait for everything to be cleaned up.
    293         waitPermissionRevoke(mFirstUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
    294         waitPermissionRevoke(mSecondUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
    295     }
    296 }
    297