Add more JobWorkItem tests.

1. Add tests for the new JobWorkItem.Builder class.
2. Add tests to ensure apps can try to persist JobWorkItems if they
   want, within the allowed parameters.

Bug: 255352252
Test: atest CtsJobSchedulerTestCases:JobWorkItemTest
Change-Id: I4a7ee902e9d84d6a52610db6d238a802bd93805c
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
index 8589732..15e67d3 100644
--- a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -124,14 +124,15 @@
             JobWorkItem work;
             int index = 0;
             while ((work = params.dequeueWork()) != null) {
-                Log.i(TAG, "Received work #" + index + ": " + work.getIntent());
+                final Intent intent = work.getIntent();
+                Log.i(TAG, "Received work #" + index + ": " + intent);
                 mReceivedWork.add(work);
 
                 int flags = 0;
 
                 if (index < expectedWork.length) {
                     TestWorkItem expected = expectedWork[index];
-                    int grantFlags = work.getIntent().getFlags();
+                    int grantFlags = intent == null ? 0 : intent.getFlags();
                     if (expected.requireUrisGranted != null) {
                         for (int ui = 0; ui < expected.requireUrisGranted.length; ui++) {
                             if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobWorkItemTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobWorkItemTest.java
index 3a52bd6..38b3ec5 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobWorkItemTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobWorkItemTest.java
@@ -21,6 +21,7 @@
 import android.app.job.JobWorkItem;
 import android.content.Intent;
 import android.jobscheduler.MockJobService;
+import android.os.PersistableBundle;
 
 import java.util.List;
 
@@ -31,7 +32,59 @@
     private static final int JOB_ID = JobWorkItemTest.class.hashCode();
     private static final Intent TEST_INTENT = new Intent("some.random.action");
 
-    public void testIntentOnlyItem() {
+    public void testAllInfoGivenToJob() throws Exception {
+        final JobInfo jobInfo = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                .setOverrideDeadline(0)
+                .build();
+        final PersistableBundle pb = new PersistableBundle();
+        pb.putInt("random_key", 42);
+        final JobWorkItem expectedJwi = new JobWorkItem.Builder()
+                .setIntent(TEST_INTENT)
+                .setExtras(pb)
+                .setEstimatedNetworkBytes(30, 20)
+                .setMinimumNetworkChunkBytes(5)
+                .build();
+        // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
+        assertEquals(0, expectedJwi.getDeliveryCount());
+
+        kTestEnvironment.setExpectedExecutions(1);
+        kTestEnvironment.setExpectedWork(new MockJobService.TestWorkItem[]{
+                new MockJobService.TestWorkItem(TEST_INTENT)});
+        kTestEnvironment.readyToWork();
+        mJobScheduler.enqueue(jobInfo, expectedJwi);
+        runSatisfiedJob(JOB_ID);
+        assertTrue("Job didn't fire immediately", kTestEnvironment.awaitExecution());
+
+        List<JobWorkItem> executedJwis = kTestEnvironment.getLastReceivedWork();
+        assertEquals(1, executedJwis.size());
+        final JobWorkItem actualJwi = executedJwis.get(0);
+        assertEquals(1, actualJwi.getDeliveryCount());
+        final Intent actualIntent = actualJwi.getIntent();
+        assertNotNull(actualIntent);
+        assertEquals(TEST_INTENT.getAction(), actualIntent.getAction());
+        final PersistableBundle extras = actualJwi.getExtras();
+        assertNotNull(extras);
+        assertEquals(1, extras.keySet().size());
+        assertEquals(42, extras.getInt("random_key"));
+        assertEquals(30, actualJwi.getEstimatedNetworkDownloadBytes());
+        assertEquals(20, actualJwi.getEstimatedNetworkUploadBytes());
+        assertEquals(5, actualJwi.getMinimumNetworkChunkBytes());
+    }
+
+    public void testIntentOnlyItem_builder() {
+        JobWorkItem jwi = new JobWorkItem.Builder().setIntent(TEST_INTENT).build();
+
+        assertEquals(TEST_INTENT, jwi.getIntent());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkDownloadBytes());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkUploadBytes());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getMinimumNetworkChunkBytes());
+        // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
+        assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
+    }
+
+    public void testIntentOnlyItem_ctor() {
         JobWorkItem jwi = new JobWorkItem(TEST_INTENT);
 
         assertEquals(TEST_INTENT, jwi.getIntent());
@@ -40,12 +93,35 @@
         assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getMinimumNetworkChunkBytes());
         // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
         assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
     }
 
-    public void testItemWithEstimatedBytes() {
-        JobWorkItem jwi = new JobWorkItem(TEST_INTENT, 10, 20);
+    public void testItemWithEstimatedBytes_builder() {
+        try {
+            new JobWorkItem.Builder().setEstimatedNetworkBytes(-10, 20).build();
+            fail("Successfully created JobWorkItem with negative download bytes value");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
 
         try {
+            new JobWorkItem.Builder().setEstimatedNetworkBytes(10, -20).build();
+            fail("Successfully created JobWorkItem with negative upload bytes value");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+
+        JobWorkItem jwi = new JobWorkItem.Builder().setEstimatedNetworkBytes(10, 20).build();
+        assertNull(jwi.getIntent());
+        assertEquals(10, jwi.getEstimatedNetworkDownloadBytes());
+        assertEquals(20, jwi.getEstimatedNetworkUploadBytes());
+        // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
+        assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
+    }
+
+    public void testItemWithEstimatedBytes_ctor() {
+        try {
             new JobWorkItem(TEST_INTENT, -10, 20);
             fail("Successfully created JobWorkItem with negative download bytes value");
         } catch (IllegalArgumentException expected) {
@@ -59,14 +135,69 @@
             // Success
         }
 
+        JobWorkItem jwi = new JobWorkItem(TEST_INTENT, 10, 20);
+
         assertEquals(TEST_INTENT, jwi.getIntent());
         assertEquals(10, jwi.getEstimatedNetworkDownloadBytes());
         assertEquals(20, jwi.getEstimatedNetworkUploadBytes());
         // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
         assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
     }
 
-    public void testItemWithMinimumChunkBytes() {
+    public void testItemWithMinimumChunkBytes_builder() {
+        JobWorkItem jwi = new JobWorkItem.Builder().setMinimumNetworkChunkBytes(3).build();
+
+        assertNull(jwi.getIntent());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkDownloadBytes());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkUploadBytes());
+        assertEquals(3, jwi.getMinimumNetworkChunkBytes());
+        // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
+        assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
+
+        try {
+            new JobWorkItem.Builder().setMinimumNetworkChunkBytes(-3).build();
+            fail("Successfully created JobWorkItem with negative minimum chunk value");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+        try {
+            new JobWorkItem.Builder().setMinimumNetworkChunkBytes(0).build();
+            fail("Successfully created JobWorkItem with 0 minimum chunk value");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+        try {
+            new JobWorkItem.Builder()
+                    .setEstimatedNetworkBytes(10, 20)
+                    .setMinimumNetworkChunkBytes(50)
+                    .build();
+            fail("Successfully created JobWorkItem with minimum chunk value too large");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+        try {
+            new JobWorkItem.Builder()
+                    .setEstimatedNetworkBytes(JobInfo.NETWORK_BYTES_UNKNOWN, 20)
+                    .setMinimumNetworkChunkBytes(25)
+                    .build();
+            fail("Successfully created JobWorkItem with minimum chunk value too large");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+        try {
+            new JobWorkItem.Builder()
+                    .setEstimatedNetworkBytes(10, JobInfo.NETWORK_BYTES_UNKNOWN)
+                    .setMinimumNetworkChunkBytes(15)
+                    .build();
+            fail("Successfully created JobWorkItem with minimum chunk value too large");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+    }
+
+    public void testItemWithMinimumChunkBytes_ctor() {
         JobWorkItem jwi = new JobWorkItem(TEST_INTENT, 10, 20, 3);
 
         assertEquals(TEST_INTENT, jwi.getIntent());
@@ -75,6 +206,7 @@
         assertEquals(3, jwi.getMinimumNetworkChunkBytes());
         // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
         assertEquals(0, jwi.getDeliveryCount());
+        assertTrue(jwi.getExtras().isEmpty());
 
         try {
             new JobWorkItem(TEST_INTENT, 10, 20, -3);
@@ -108,6 +240,30 @@
         }
     }
 
+    public void testItemWithPersistableBundle() {
+        final PersistableBundle pb = new PersistableBundle();
+        pb.putInt("random_key", 42);
+        JobWorkItem jwi = new JobWorkItem.Builder().setExtras(pb).build();
+
+        assertNull(jwi.getIntent());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkDownloadBytes());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getEstimatedNetworkUploadBytes());
+        assertEquals(JobInfo.NETWORK_BYTES_UNKNOWN, jwi.getMinimumNetworkChunkBytes());
+        // JobWorkItem hasn't been scheduled yet. Delivery count should be 0.
+        assertEquals(0, jwi.getDeliveryCount());
+        final PersistableBundle extras = jwi.getExtras();
+        assertNotNull(extras);
+        assertEquals(1, extras.keySet().size());
+        assertEquals(42, extras.getInt("random_key"));
+
+        try {
+            new JobWorkItem.Builder().setExtras(null).build();
+            fail("Successfully created null extras");
+        } catch (Exception expected) {
+            // Success
+        }
+    }
+
     public void testDeliveryCountBumped() throws Exception {
         JobInfo jobInfo = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
                 .setOverrideDeadline(0)
@@ -129,6 +285,30 @@
         assertEquals(1, executedJWIs.get(0).getDeliveryCount());
     }
 
+    public void testPersisted_withIntent() {
+        JobWorkItem jwi = new JobWorkItem.Builder().setIntent(TEST_INTENT).build();
+        JobInfo jobInfo = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
+                .setPersisted(true)
+                .build();
+        try {
+            mJobScheduler.enqueue(jobInfo, jwi);
+            fail("Successfully enqueued persisted JWI with intent");
+        } catch (IllegalArgumentException expected) {
+            // Success
+        }
+    }
+
+    public void testPersisted_withPersistableBundle() {
+        final PersistableBundle pb = new PersistableBundle();
+        pb.putInt("random_key", 42);
+        JobWorkItem jwi = new JobWorkItem.Builder().setExtras(pb).build();
+        JobInfo jobInfo = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
+                .setPersisted(true)
+                .build();
+
+        assertEquals(JobScheduler.RESULT_SUCCESS, mJobScheduler.enqueue(jobInfo, jwi));
+    }
+
     public void testScheduleItemWithNetworkInfoAndNoNetworkConstraint_download() {
         JobWorkItem jwi = new JobWorkItem(TEST_INTENT, 10, JobInfo.NETWORK_BYTES_UNKNOWN);
         JobInfo jobInfo = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
diff --git a/tests/JobSchedulerSharedUid/src/android/jobscheduler/MockJobService.java b/tests/JobSchedulerSharedUid/src/android/jobscheduler/MockJobService.java
index cb5a2da..4f2b6d7 100644
--- a/tests/JobSchedulerSharedUid/src/android/jobscheduler/MockJobService.java
+++ b/tests/JobSchedulerSharedUid/src/android/jobscheduler/MockJobService.java
@@ -103,14 +103,15 @@
             JobWorkItem work;
             int index = 0;
             while ((work = params.dequeueWork()) != null) {
-                Log.i(TAG, "Received work #" + index + ": " + work.getIntent());
+                final Intent intent = work.getIntent();
+                Log.i(TAG, "Received work #" + index + ": " + intent);
                 mReceivedWork.add(work);
 
                 int flags = 0;
 
                 if (index < expectedWork.length) {
                     TestWorkItem expected = expectedWork[index];
-                    int grantFlags = work.getIntent().getFlags();
+                    int grantFlags = intent == null ? 0 : intent.getFlags();
                     if (expected.requireUrisGranted != null) {
                         for (int ui = 0; ui < expected.requireUrisGranted.length; ui++) {
                             if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {