WorkManagerImplTest.java revision 70c57725ae84e0e8f8981c076876f67560059111
1/*
2 * Copyright 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
17package androidx.work.impl;
18
19import static androidx.work.ExistingWorkPolicy.APPEND;
20import static androidx.work.ExistingWorkPolicy.KEEP;
21import static androidx.work.ExistingWorkPolicy.REPLACE;
22import static androidx.work.NetworkType.METERED;
23import static androidx.work.NetworkType.NOT_REQUIRED;
24import static androidx.work.State.BLOCKED;
25import static androidx.work.State.CANCELLED;
26import static androidx.work.State.ENQUEUED;
27import static androidx.work.State.FAILED;
28import static androidx.work.State.RUNNING;
29import static androidx.work.State.SUCCEEDED;
30
31import static org.hamcrest.CoreMatchers.is;
32import static org.hamcrest.CoreMatchers.not;
33import static org.hamcrest.CoreMatchers.notNullValue;
34import static org.hamcrest.CoreMatchers.nullValue;
35import static org.hamcrest.MatcherAssert.assertThat;
36import static org.hamcrest.Matchers.containsInAnyOrder;
37import static org.hamcrest.Matchers.emptyCollectionOf;
38import static org.hamcrest.Matchers.greaterThanOrEqualTo;
39import static org.hamcrest.Matchers.isIn;
40import static org.hamcrest.Matchers.isOneOf;
41import static org.mockito.Mockito.clearInvocations;
42import static org.mockito.Mockito.mock;
43import static org.mockito.Mockito.times;
44import static org.mockito.Mockito.verify;
45
46import android.arch.core.executor.ArchTaskExecutor;
47import android.arch.core.executor.TaskExecutor;
48import android.arch.lifecycle.LiveData;
49import android.arch.lifecycle.Observer;
50import android.arch.persistence.db.SupportSQLiteDatabase;
51import android.arch.persistence.db.SupportSQLiteOpenHelper;
52import android.content.Context;
53import android.net.Uri;
54import android.os.Build;
55import android.provider.MediaStore;
56import android.support.annotation.NonNull;
57import android.support.test.InstrumentationRegistry;
58import android.support.test.filters.LargeTest;
59import android.support.test.filters.SdkSuppress;
60import android.support.test.filters.SmallTest;
61import android.support.test.runner.AndroidJUnit4;
62
63import androidx.work.BackoffPolicy;
64import androidx.work.Configuration;
65import androidx.work.Constraints;
66import androidx.work.ContentUriTriggers;
67import androidx.work.Data;
68import androidx.work.OneTimeWorkRequest;
69import androidx.work.PeriodicWorkRequest;
70import androidx.work.TestLifecycleOwner;
71import androidx.work.WorkContinuation;
72import androidx.work.WorkRequest;
73import androidx.work.WorkStatus;
74import androidx.work.impl.model.Dependency;
75import androidx.work.impl.model.DependencyDao;
76import androidx.work.impl.model.WorkName;
77import androidx.work.impl.model.WorkSpec;
78import androidx.work.impl.model.WorkSpecDao;
79import androidx.work.impl.model.WorkTag;
80import androidx.work.impl.model.WorkTagDao;
81import androidx.work.impl.utils.taskexecutor.InstantTaskExecutorRule;
82import androidx.work.impl.workers.ConstraintTrackingWorker;
83import androidx.work.worker.InfiniteTestWorker;
84import androidx.work.worker.TestWorker;
85
86import org.junit.After;
87import org.junit.Before;
88import org.junit.Rule;
89import org.junit.Test;
90import org.junit.runner.RunWith;
91import org.mockito.ArgumentCaptor;
92
93import java.util.Arrays;
94import java.util.Collections;
95import java.util.List;
96import java.util.UUID;
97import java.util.concurrent.Executors;
98import java.util.concurrent.TimeUnit;
99
100@RunWith(AndroidJUnit4.class)
101public class WorkManagerImplTest {
102
103    private WorkDatabase mDatabase;
104    private WorkManagerImpl mWorkManagerImpl;
105
106    @Rule
107    public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule();
108
109    @Before
110    public void setUp() {
111        ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
112            @Override
113            public void executeOnDiskIO(@NonNull Runnable runnable) {
114                runnable.run();
115            }
116
117            @Override
118            public void postToMainThread(@NonNull Runnable runnable) {
119                runnable.run();
120            }
121
122            @Override
123            public boolean isMainThread() {
124                return true;
125            }
126        });
127
128        Context context = InstrumentationRegistry.getTargetContext();
129        Configuration configuration = new Configuration.Builder()
130                .withExecutor(Executors.newSingleThreadExecutor())
131                .build();
132        mWorkManagerImpl = new WorkManagerImpl(context, configuration);
133        WorkManagerImpl.setDelegate(mWorkManagerImpl);
134        mDatabase = mWorkManagerImpl.getWorkDatabase();
135    }
136
137    @After
138    public void tearDown() {
139        WorkManagerImpl.setDelegate(null);
140        ArchTaskExecutor.getInstance().setDelegate(null);
141    }
142
143    @Test
144    @SmallTest
145    public void testEnqueue_insertWork() throws InterruptedException {
146        final int workCount = 3;
147        final OneTimeWorkRequest[] workArray = new OneTimeWorkRequest[workCount];
148        for (int i = 0; i < workCount; ++i) {
149            workArray[i] = new OneTimeWorkRequest.Builder(TestWorker.class).build();
150        }
151
152        mWorkManagerImpl.beginWith(workArray[0]).then(workArray[1])
153                .then(workArray[2])
154                .synchronous().enqueueSync();
155
156        for (int i = 0; i < workCount; ++i) {
157            String id = workArray[i].getStringId();
158            assertThat(mDatabase.workSpecDao().getWorkSpec(id), is(notNullValue()));
159            assertThat(
160                    "index " + i + " does not have expected number of dependencies!",
161                    mDatabase.dependencyDao().getPrerequisites(id).size() > 0,
162                    is(i > 0));
163        }
164    }
165
166    @Test
167    @SmallTest
168    public void testEnqueue_insertMultipleWork() {
169        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
170        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
171        OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
172
173        mWorkManagerImpl.synchronous().enqueueSync(work1, work2, work3);
174
175        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
176        assertThat(workSpecDao.getWorkSpec(work1.getStringId()), is(notNullValue()));
177        assertThat(workSpecDao.getWorkSpec(work2.getStringId()), is(notNullValue()));
178        assertThat(workSpecDao.getWorkSpec(work3.getStringId()), is(notNullValue()));
179    }
180
181    @Test
182    @SmallTest
183    public void testEnqueue_insertMultipleWork_continuationBlocking() {
184        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
185        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
186        OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
187
188        mWorkManagerImpl.beginWith(work1, work2, work3)
189                .synchronous()
190                .enqueueSync();
191
192        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
193        assertThat(workSpecDao.getWorkSpec(work1.getStringId()), is(notNullValue()));
194        assertThat(workSpecDao.getWorkSpec(work2.getStringId()), is(notNullValue()));
195        assertThat(workSpecDao.getWorkSpec(work3.getStringId()), is(notNullValue()));
196    }
197
198    @Test
199    @SmallTest
200    public void testEnqueue_insertWithDependencies() {
201        OneTimeWorkRequest work1a = new OneTimeWorkRequest.Builder(TestWorker.class).build();
202        OneTimeWorkRequest work1b = new OneTimeWorkRequest.Builder(TestWorker.class).build();
203        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
204        OneTimeWorkRequest work3a = new OneTimeWorkRequest.Builder(TestWorker.class).build();
205        OneTimeWorkRequest work3b = new OneTimeWorkRequest.Builder(TestWorker.class).build();
206
207        mWorkManagerImpl.beginWith(work1a, work1b).then(work2)
208                .then(work3a, work3b)
209                .synchronous()
210                .enqueueSync();
211
212        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
213        assertThat(workSpecDao.getWorkSpec(work1a.getStringId()), is(notNullValue()));
214        assertThat(workSpecDao.getWorkSpec(work1b.getStringId()), is(notNullValue()));
215        assertThat(workSpecDao.getWorkSpec(work2.getStringId()), is(notNullValue()));
216        assertThat(workSpecDao.getWorkSpec(work3a.getStringId()), is(notNullValue()));
217        assertThat(workSpecDao.getWorkSpec(work3b.getStringId()), is(notNullValue()));
218
219        DependencyDao dependencyDao = mDatabase.dependencyDao();
220        assertThat(dependencyDao.getPrerequisites(work1a.getStringId()),
221                is(emptyCollectionOf(String.class)));
222        assertThat(dependencyDao.getPrerequisites(work1b.getStringId()),
223                is(emptyCollectionOf(String.class)));
224
225        List<String> prerequisites = dependencyDao.getPrerequisites(work2.getStringId());
226        assertThat(prerequisites, containsInAnyOrder(work1a.getStringId(), work1b.getStringId()));
227
228        prerequisites = dependencyDao.getPrerequisites(work3a.getStringId());
229        assertThat(prerequisites, containsInAnyOrder(work2.getStringId()));
230
231        prerequisites = dependencyDao.getPrerequisites(work3b.getStringId());
232        assertThat(prerequisites, containsInAnyOrder(work2.getStringId()));
233    }
234
235    @Test
236    @SmallTest
237    public void testEnqueue_insertWithCompletedDependencies_isNotStatusBlocked() {
238        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
239                .setInitialState(SUCCEEDED)
240                .build();
241
242        WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1);
243        workContinuation.synchronous().enqueueSync();
244        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
245        assertThat(workSpecDao.getState(work1.getStringId()), is(SUCCEEDED));
246
247        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
248        workContinuation.then(work2).synchronous().enqueueSync();
249        assertThat(workSpecDao.getState(work2.getStringId()), isOneOf(ENQUEUED, RUNNING));
250    }
251
252    @Test
253    @SmallTest
254    public void testEnqueue_insertWithFailedDependencies_isStatusFailed() {
255        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
256                .setInitialState(FAILED)
257                .build();
258
259        WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1);
260        workContinuation.synchronous().enqueueSync();
261        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
262        assertThat(workSpecDao.getState(work1.getStringId()), is(FAILED));
263
264        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
265        workContinuation.then(work2).synchronous().enqueueSync();
266        assertThat(workSpecDao.getState(work2.getStringId()), is(FAILED));
267    }
268
269    @Test
270    @SmallTest
271    public void testEnqueue_insertWithCancelledDependencies_isStatusCancelled() {
272        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
273                .setInitialState(CANCELLED)
274                .build();
275
276        WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1);
277        workContinuation.synchronous().enqueueSync();
278        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
279        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
280
281        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
282        workContinuation.then(work2).synchronous().enqueueSync();
283        assertThat(workSpecDao.getState(work2.getStringId()), is(CANCELLED));
284    }
285
286    @Test
287    @SmallTest
288    @SdkSuppress(minSdkVersion = 23)
289    public void testEnqueue_insertWorkConstraints() {
290        Uri testUri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
291        Uri testUri2 = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
292
293        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
294                .setConstraints(
295                        new Constraints.Builder()
296                                .setRequiresCharging(true)
297                                .setRequiresDeviceIdle(true)
298                                .setRequiredNetworkType(METERED)
299                                .setRequiresBatteryNotLow(true)
300                                .setRequiresStorageNotLow(true)
301                                .addContentUriTrigger(testUri1, true)
302                                .addContentUriTrigger(testUri2, false)
303                                .build())
304                .build();
305        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
306        mWorkManagerImpl.beginWith(work0).then(work1).synchronous().enqueueSync();
307
308        WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getStringId());
309        WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getStringId());
310
311        ContentUriTriggers expectedTriggers = new ContentUriTriggers();
312        expectedTriggers.add(testUri1, true);
313        expectedTriggers.add(testUri2, false);
314
315        Constraints constraints = workSpec0.constraints;
316        assertThat(constraints, is(notNullValue()));
317        assertThat(constraints.requiresCharging(), is(true));
318        assertThat(constraints.requiresDeviceIdle(), is(true));
319        assertThat(constraints.requiresBatteryNotLow(), is(true));
320        assertThat(constraints.requiresStorageNotLow(), is(true));
321        assertThat(constraints.getRequiredNetworkType(), is(METERED));
322        if (Build.VERSION.SDK_INT >= 24) {
323            assertThat(constraints.getContentUriTriggers(), is(expectedTriggers));
324        } else {
325            assertThat(constraints.getContentUriTriggers(), is(new ContentUriTriggers()));
326        }
327
328        constraints = workSpec1.constraints;
329        assertThat(constraints, is(notNullValue()));
330        assertThat(constraints.requiresCharging(), is(false));
331        assertThat(constraints.requiresDeviceIdle(), is(false));
332        assertThat(constraints.requiresBatteryNotLow(), is(false));
333        assertThat(constraints.requiresStorageNotLow(), is(false));
334        assertThat(constraints.getRequiredNetworkType(), is(NOT_REQUIRED));
335        assertThat(constraints.getContentUriTriggers().size(), is(0));
336    }
337
338    @Test
339    @SmallTest
340    public void testEnqueue_insertWorkInitialDelay() {
341        final long expectedInitialDelay = 5000L;
342        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
343                .setInitialDelay(expectedInitialDelay, TimeUnit.MILLISECONDS)
344                .build();
345        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
346        mWorkManagerImpl.beginWith(work0).then(work1).synchronous().enqueueSync();
347
348        WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getStringId());
349        WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getStringId());
350
351        assertThat(workSpec0.initialDelay, is(expectedInitialDelay));
352        assertThat(workSpec1.initialDelay, is(0L));
353    }
354
355    @Test
356    @SmallTest
357    public void testEnqueue_insertWorkBackoffPolicy() {
358        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
359                .setBackoffCriteria(BackoffPolicy.LINEAR, 50000, TimeUnit.MILLISECONDS)
360                .build();
361        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
362        mWorkManagerImpl.beginWith(work0).then(work1).synchronous().enqueueSync();
363
364        WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getStringId());
365        WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getStringId());
366
367        assertThat(workSpec0.backoffPolicy, is(BackoffPolicy.LINEAR));
368        assertThat(workSpec0.backoffDelayDuration, is(50000L));
369
370        assertThat(workSpec1.backoffPolicy, is(BackoffPolicy.EXPONENTIAL));
371        assertThat(workSpec1.backoffDelayDuration,
372                is(WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS));
373    }
374
375    @Test
376    @SmallTest
377    public void testEnqueue_insertWorkTags() {
378        final String firstTag = "first_tag";
379        final String secondTag = "second_tag";
380        final String thirdTag = "third_tag";
381
382        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
383                .addTag(firstTag)
384                .addTag(secondTag)
385                .build();
386        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
387                .addTag(firstTag)
388                .build();
389        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
390        mWorkManagerImpl.beginWith(work0).then(work1).then(work2).synchronous().enqueueSync();
391
392        WorkTagDao workTagDao = mDatabase.workTagDao();
393        assertThat(workTagDao.getWorkSpecIdsWithTag(firstTag),
394                containsInAnyOrder(work0.getStringId(), work1.getStringId()));
395        assertThat(workTagDao.getWorkSpecIdsWithTag(secondTag),
396                containsInAnyOrder(work0.getStringId()));
397        assertThat(workTagDao.getWorkSpecIdsWithTag(thirdTag), emptyCollectionOf(String.class));
398    }
399
400    @Test
401    @SmallTest
402    public void testEnqueue_insertPeriodicWork() {
403        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
404                TestWorker.class,
405                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
406                TimeUnit.MILLISECONDS)
407                .build();
408
409        mWorkManagerImpl.synchronous().enqueueSync(periodicWork);
410
411        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getStringId());
412        assertThat(workSpec.isPeriodic(), is(true));
413        assertThat(workSpec.intervalDuration, is(PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS));
414        assertThat(workSpec.flexDuration, is(PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS));
415    }
416
417    @Test
418    @SmallTest
419    public void testEnqueued_work_setsPeriodStartTime() {
420        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
421        assertThat(work.getWorkSpec().periodStartTime, is(0L));
422
423        long beforeEnqueueTime = System.currentTimeMillis();
424
425        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
426        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
427        assertThat(workSpec.periodStartTime, is(greaterThanOrEqualTo(beforeEnqueueTime)));
428    }
429
430    @Test
431    @SmallTest
432    public void testEnqueued_periodicWork_setsPeriodStartTime() {
433        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
434                TestWorker.class,
435                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
436                TimeUnit.MILLISECONDS)
437                .build();
438        assertThat(periodicWork.getWorkSpec().periodStartTime, is(0L));
439
440        long beforeEnqueueTime = System.currentTimeMillis();
441
442        mWorkManagerImpl.synchronous().enqueueSync(periodicWork);
443
444        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getStringId());
445        assertThat(workSpec.periodStartTime, is(greaterThanOrEqualTo(beforeEnqueueTime)));
446    }
447
448    @Test
449    @SmallTest
450    public void testBeginWithName_setsUniqueName() {
451        final String testName = "myname";
452
453        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
454        mWorkManagerImpl.beginUniqueWork(testName, REPLACE)
455                .then(work)
456                .synchronous()
457                .enqueueSync();
458
459        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
460        assertThat(work.getStringId(), isIn(workSpecIds));
461    }
462
463    @Test
464    @SmallTest
465    public void testBeginWithName_deletesOldWorkOnReplace() {
466        final String testName = "myname";
467
468        OneTimeWorkRequest originalWork =
469                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
470        insertNamedWorks(testName, originalWork);
471
472        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
473        assertThat(workSpecIds, containsInAnyOrder(originalWork.getStringId()));
474
475        OneTimeWorkRequest replacementWork1 =
476                new OneTimeWorkRequest.Builder(TestWorker.class).build();
477        OneTimeWorkRequest replacementWork2 =
478                new OneTimeWorkRequest.Builder(TestWorker.class).build();
479        mWorkManagerImpl
480                .beginUniqueWork(testName, REPLACE, replacementWork1)
481                .then(replacementWork2)
482                .synchronous()
483                .enqueueSync();
484
485        workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
486        assertThat(
487                workSpecIds,
488                containsInAnyOrder(replacementWork1.getStringId(), replacementWork2.getStringId()));
489
490        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
491        assertThat(workSpecDao.getWorkSpec(originalWork.getStringId()), is(nullValue()));
492        assertThat(workSpecDao.getWorkSpec(replacementWork1.getStringId()), is(not(nullValue())));
493        assertThat(workSpecDao.getWorkSpec(replacementWork2.getStringId()), is(not(nullValue())));
494    }
495
496    @Test
497    @SmallTest
498    public void testBeginWithName_keepsExistingWorkOnKeep() {
499        final String testName = "myname";
500
501        OneTimeWorkRequest originalWork =
502                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
503        insertNamedWorks(testName, originalWork);
504
505        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
506        assertThat(workSpecIds, containsInAnyOrder(originalWork.getStringId()));
507
508        OneTimeWorkRequest replacementWork1 =
509                new OneTimeWorkRequest.Builder(TestWorker.class).build();
510        OneTimeWorkRequest replacementWork2 =
511                new OneTimeWorkRequest.Builder(TestWorker.class).build();
512        mWorkManagerImpl
513                .beginUniqueWork(testName, KEEP, replacementWork1)
514                .then(replacementWork2)
515                .synchronous()
516                .enqueueSync();
517
518        workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
519        assertThat(workSpecIds, containsInAnyOrder(originalWork.getStringId()));
520
521        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
522        assertThat(workSpecDao.getWorkSpec(originalWork.getStringId()), is(not(nullValue())));
523        assertThat(workSpecDao.getWorkSpec(replacementWork1.getStringId()), is(nullValue()));
524        assertThat(workSpecDao.getWorkSpec(replacementWork2.getStringId()), is(nullValue()));
525    }
526
527    @Test
528    @SmallTest
529    public void testBeginWithName_replacesExistingWorkOnKeepWhenExistingWorkIsFinished() {
530        final String testName = "myname";
531
532        OneTimeWorkRequest originalWork = new OneTimeWorkRequest.Builder(TestWorker.class)
533                .setInitialState(SUCCEEDED)
534                .build();
535        insertNamedWorks(testName, originalWork);
536
537        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
538        assertThat(workSpecIds, containsInAnyOrder(originalWork.getStringId()));
539
540        OneTimeWorkRequest replacementWork1 =
541                new OneTimeWorkRequest.Builder(TestWorker.class).build();
542        OneTimeWorkRequest replacementWork2 =
543                new OneTimeWorkRequest.Builder(TestWorker.class).build();
544        mWorkManagerImpl
545                .beginUniqueWork(testName, KEEP, replacementWork1)
546                .then(replacementWork2)
547                .synchronous()
548                .enqueueSync();
549
550        workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
551        assertThat(workSpecIds,
552                containsInAnyOrder(replacementWork1.getStringId(), replacementWork2.getStringId()));
553
554        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
555        assertThat(workSpecDao.getWorkSpec(originalWork.getStringId()), is(nullValue()));
556        assertThat(workSpecDao.getWorkSpec(replacementWork1.getStringId()), is(not(nullValue())));
557        assertThat(workSpecDao.getWorkSpec(replacementWork2.getStringId()), is(not(nullValue())));
558    }
559
560    @Test
561    @SmallTest
562    public void testBeginWithName_appendsExistingWorkOnAppend() {
563        final String testName = "myname";
564
565        OneTimeWorkRequest originalWork =
566                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
567        insertNamedWorks(testName, originalWork);
568
569        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
570        assertThat(workSpecIds, containsInAnyOrder(originalWork.getStringId()));
571
572        OneTimeWorkRequest appendWork1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
573        OneTimeWorkRequest appendWork2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
574        mWorkManagerImpl
575                .beginUniqueWork(testName, APPEND, appendWork1)
576                .then(appendWork2)
577                .synchronous()
578                .enqueueSync();
579
580        workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
581        assertThat(workSpecIds,
582                containsInAnyOrder(
583                        originalWork.getStringId(),
584                        appendWork1.getStringId(),
585                        appendWork2.getStringId()));
586
587        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
588        assertThat(workSpecDao.getWorkSpec(originalWork.getStringId()), is(not(nullValue())));
589        assertThat(workSpecDao.getState(appendWork1.getStringId()), is(BLOCKED));
590        assertThat(workSpecDao.getState(appendWork2.getStringId()), is(BLOCKED));
591
592        assertThat(mDatabase.dependencyDao().getDependentWorkIds(originalWork.getStringId()),
593                containsInAnyOrder(appendWork1.getStringId()));
594    }
595
596    @Test
597    @SmallTest
598    public void testBeginWithName_appendsExistingWorkToOnlyLeavesOnAppend() {
599        final String testName = "myname";
600
601        OneTimeWorkRequest originalWork1 =
602                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
603        OneTimeWorkRequest originalWork2 =
604                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
605        OneTimeWorkRequest originalWork3 =
606                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
607        OneTimeWorkRequest originalWork4 =
608                new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
609
610        insertNamedWorks(testName, originalWork1, originalWork2, originalWork3, originalWork4);
611        insertDependency(originalWork4, originalWork2);
612        insertDependency(originalWork3, originalWork2);
613        insertDependency(originalWork2, originalWork1);
614
615        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
616        assertThat(workSpecIds,
617                containsInAnyOrder(
618                        originalWork1.getStringId(),
619                        originalWork2.getStringId(),
620                        originalWork3.getStringId(),
621                        originalWork4.getStringId()));
622
623        OneTimeWorkRequest appendWork1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
624        OneTimeWorkRequest appendWork2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
625        mWorkManagerImpl
626                .beginUniqueWork(testName, APPEND, appendWork1)
627                .then(appendWork2)
628                .synchronous()
629                .enqueueSync();
630
631        workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
632        assertThat(workSpecIds,
633                containsInAnyOrder(
634                        originalWork1.getStringId(),
635                        originalWork2.getStringId(),
636                        originalWork3.getStringId(),
637                        originalWork4.getStringId(),
638                        appendWork1.getStringId(),
639                        appendWork2.getStringId()));
640
641        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
642        assertThat(workSpecDao.getWorkSpec(originalWork1.getStringId()), is(not(nullValue())));
643        assertThat(workSpecDao.getWorkSpec(originalWork2.getStringId()), is(not(nullValue())));
644        assertThat(workSpecDao.getWorkSpec(originalWork3.getStringId()), is(not(nullValue())));
645        assertThat(workSpecDao.getWorkSpec(originalWork4.getStringId()), is(not(nullValue())));
646        assertThat(workSpecDao.getState(appendWork1.getStringId()), is(BLOCKED));
647        assertThat(workSpecDao.getState(appendWork2.getStringId()), is(BLOCKED));
648
649        DependencyDao dependencyDao = mDatabase.dependencyDao();
650        assertThat(dependencyDao.getPrerequisites(appendWork1.getStringId()),
651                containsInAnyOrder(originalWork3.getStringId(), originalWork4.getStringId()));
652        assertThat(dependencyDao.getPrerequisites(appendWork2.getStringId()),
653                containsInAnyOrder(appendWork1.getStringId()));
654    }
655
656    @Test
657    @SmallTest
658    public void testBeginWithName_insertsExistingWorkWhenNothingToAppendTo() {
659        final String testName = "myname";
660
661        OneTimeWorkRequest appendWork1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
662        OneTimeWorkRequest appendWork2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
663        mWorkManagerImpl
664                .beginUniqueWork(testName, APPEND, appendWork1)
665                .then(appendWork2)
666                .synchronous()
667                .enqueueSync();
668
669        List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName);
670        assertThat(workSpecIds,
671                containsInAnyOrder(appendWork1.getStringId(), appendWork2.getStringId()));
672    }
673
674    @Test
675    @SmallTest
676    public void testGetStatusByIdSync() {
677        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
678                .setInitialState(SUCCEEDED)
679                .build();
680        insertWorkSpecAndTags(work);
681
682        WorkStatus workStatus = mWorkManagerImpl.getStatusByIdSync(work.getId());
683        assertThat(workStatus.getId().toString(), is(work.getStringId()));
684        assertThat(workStatus.getState(), is(SUCCEEDED));
685    }
686
687    @Test
688    @SmallTest
689    public void testGetStatusByIdSync_returnsNullIfNotInDatabase() {
690        WorkStatus workStatus = mWorkManagerImpl.getStatusByIdSync(UUID.randomUUID());
691        assertThat(workStatus, is(nullValue()));
692    }
693
694    @Test
695    @SmallTest
696    @SuppressWarnings("unchecked")
697    public void testGetStatusesById() {
698        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
699        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
700        insertWorkSpecAndTags(work0);
701        insertWorkSpecAndTags(work1);
702
703        Observer<List<WorkStatus>> mockObserver = mock(Observer.class);
704
705        TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner();
706        LiveData<List<WorkStatus>> liveData = mWorkManagerImpl.getStatusesById(
707                Arrays.asList(work0.getStringId(), work1.getStringId()));
708        liveData.observe(testLifecycleOwner, mockObserver);
709
710        ArgumentCaptor<List<WorkStatus>> captor = ArgumentCaptor.forClass(List.class);
711        verify(mockObserver).onChanged(captor.capture());
712        assertThat(captor.getValue(), is(not(nullValue())));
713        assertThat(captor.getValue().size(), is(2));
714
715        WorkStatus workStatus0 = new WorkStatus(
716                work0.getId(),
717                ENQUEUED,
718                Data.EMPTY,
719                Collections.<String>emptyList());
720        WorkStatus workStatus1 = new WorkStatus(
721                work1.getId(),
722                ENQUEUED,
723                Data.EMPTY,
724                Collections.<String>emptyList());
725        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1));
726
727        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
728        workSpecDao.setState(RUNNING, work0.getStringId());
729
730        verify(mockObserver, times(2)).onChanged(captor.capture());
731        assertThat(captor.getValue(), is(not(nullValue())));
732        assertThat(captor.getValue().size(), is(2));
733
734        workStatus0 = new WorkStatus(
735                work0.getId(),
736                RUNNING,
737                Data.EMPTY,
738                Collections.<String>emptyList());
739        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1));
740
741        clearInvocations(mockObserver);
742        workSpecDao.setState(RUNNING, work1.getStringId());
743
744        verify(mockObserver).onChanged(captor.capture());
745        assertThat(captor.getValue(), is(not(nullValue())));
746        assertThat(captor.getValue().size(), is(2));
747
748        workStatus1 = new WorkStatus(
749                work1.getId(),
750                RUNNING,
751                Data.EMPTY,
752                Collections.<String>emptyList());
753        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1));
754
755        liveData.removeObservers(testLifecycleOwner);
756    }
757
758    @Test
759    @SmallTest
760    public void testGetStatusesByTagSync() {
761        final String firstTag = "first_tag";
762        final String secondTag = "second_tag";
763
764        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
765                .addTag(firstTag)
766                .addTag(secondTag)
767                .setInitialState(RUNNING)
768                .build();
769        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
770                .addTag(firstTag)
771                .setInitialState(BLOCKED)
772                .build();
773        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
774                .addTag(secondTag)
775                .setInitialState(SUCCEEDED)
776                .build();
777        insertWorkSpecAndTags(work0);
778        insertWorkSpecAndTags(work1);
779        insertWorkSpecAndTags(work2);
780
781        WorkStatus workStatus0 = new WorkStatus(
782                work0.getId(),
783                RUNNING,
784                Data.EMPTY,
785                Arrays.asList(firstTag, secondTag));
786        WorkStatus workStatus1 = new WorkStatus(
787                work1.getId(),
788                BLOCKED,
789                Data.EMPTY,
790                Collections.singletonList(firstTag));
791        WorkStatus workStatus2 = new WorkStatus(
792                work2.getId(),
793                SUCCEEDED,
794                Data.EMPTY,
795                Collections.singletonList(secondTag));
796
797        List<WorkStatus> workStatuses = mWorkManagerImpl.getStatusesByTagSync(firstTag);
798        assertThat(workStatuses, containsInAnyOrder(workStatus0, workStatus1));
799
800        workStatuses = mWorkManagerImpl.getStatusesByTagSync(secondTag);
801        assertThat(workStatuses, containsInAnyOrder(workStatus0, workStatus2));
802
803        workStatuses = mWorkManagerImpl.getStatusesByTagSync("dummy");
804        assertThat(workStatuses.size(), is(0));
805    }
806
807    @Test
808    @SmallTest
809    @SuppressWarnings("unchecked")
810    public void testGetStatusesByTag() {
811        final String firstTag = "first_tag";
812        final String secondTag = "second_tag";
813        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
814
815        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
816                .addTag(firstTag)
817                .addTag(secondTag)
818                .setInitialState(RUNNING)
819                .build();
820        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
821                .addTag(firstTag)
822                .setInitialState(BLOCKED)
823                .build();
824        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
825                .addTag(secondTag)
826                .setInitialState(SUCCEEDED)
827                .build();
828        insertWorkSpecAndTags(work0);
829        insertWorkSpecAndTags(work1);
830        insertWorkSpecAndTags(work2);
831
832        Observer<List<WorkStatus>> mockObserver = mock(Observer.class);
833
834        TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner();
835        LiveData<List<WorkStatus>> liveData = mWorkManagerImpl.getStatusesByTag(firstTag);
836        liveData.observe(testLifecycleOwner, mockObserver);
837
838        ArgumentCaptor<List<WorkStatus>> captor = ArgumentCaptor.forClass(List.class);
839        verify(mockObserver).onChanged(captor.capture());
840        assertThat(captor.getValue(), is(not(nullValue())));
841        assertThat(captor.getValue().size(), is(2));
842
843        WorkStatus workStatus0 = new WorkStatus(
844                work0.getId(),
845                RUNNING,
846                Data.EMPTY,
847                Arrays.asList(firstTag, secondTag));
848        WorkStatus workStatus1 = new WorkStatus(
849                work1.getId(),
850                BLOCKED,
851                Data.EMPTY,
852                Collections.singletonList(firstTag));
853        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1));
854
855        workSpecDao.setState(ENQUEUED, work0.getStringId());
856
857        verify(mockObserver, times(2)).onChanged(captor.capture());
858        assertThat(captor.getValue(), is(not(nullValue())));
859        assertThat(captor.getValue().size(), is(2));
860
861        workStatus0 = new WorkStatus(
862                work0.getId(),
863                ENQUEUED,
864                Data.EMPTY,
865                Arrays.asList(firstTag, secondTag));
866        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1));
867
868        liveData.removeObservers(testLifecycleOwner);
869    }
870
871    @Test
872    @SmallTest
873    public void getStatusByNameSync() {
874        final String testName = "myname";
875
876        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
877                .setInitialState(RUNNING)
878                .build();
879        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
880                .setInitialState(BLOCKED)
881                .build();
882        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
883                .setInitialState(BLOCKED)
884                .build();
885        insertNamedWorks(testName, work0, work1, work2);
886        insertDependency(work1, work0);
887        insertDependency(work2, work1);
888
889        WorkStatus workStatus0 = new WorkStatus(
890                work0.getId(),
891                RUNNING,
892                Data.EMPTY,
893                Collections.<String>emptyList());
894        WorkStatus workStatus1 = new WorkStatus(
895                work1.getId(),
896                BLOCKED,
897                Data.EMPTY,
898                Collections.<String>emptyList());
899        WorkStatus workStatus2 = new WorkStatus(
900                work2.getId(),
901                BLOCKED,
902                Data.EMPTY,
903                Collections.<String>emptyList());
904
905        List<WorkStatus> workStatuses = mWorkManagerImpl.getStatusesForUniqueWorkSync(testName);
906        assertThat(workStatuses, containsInAnyOrder(workStatus0, workStatus1, workStatus2));
907
908        workStatuses = mWorkManagerImpl.getStatusesForUniqueWorkSync("dummy");
909        assertThat(workStatuses.size(), is(0));
910    }
911
912    @Test
913    @SmallTest
914    @SuppressWarnings("unchecked")
915    public void testGetStatusesByName() {
916        final String testName = "myname";
917        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
918
919        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
920                .setInitialState(RUNNING)
921                .build();
922        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
923                .setInitialState(BLOCKED)
924                .build();
925        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
926                .setInitialState(BLOCKED)
927                .build();
928        insertNamedWorks(testName, work0, work1, work2);
929        insertDependency(work1, work0);
930        insertDependency(work2, work1);
931
932        Observer<List<WorkStatus>> mockObserver = mock(Observer.class);
933
934        TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner();
935        LiveData<List<WorkStatus>> liveData = mWorkManagerImpl.getStatusesForUniqueWork(testName);
936        liveData.observe(testLifecycleOwner, mockObserver);
937
938        ArgumentCaptor<List<WorkStatus>> captor = ArgumentCaptor.forClass(List.class);
939        verify(mockObserver).onChanged(captor.capture());
940        assertThat(captor.getValue(), is(not(nullValue())));
941        assertThat(captor.getValue().size(), is(3));
942
943        WorkStatus workStatus0 = new WorkStatus(
944                work0.getId(),
945                RUNNING,
946                Data.EMPTY,
947                Collections.<String>emptyList());
948        WorkStatus workStatus1 = new WorkStatus(
949                work1.getId(),
950                BLOCKED,
951                Data.EMPTY,
952                Collections.<String>emptyList());
953        WorkStatus workStatus2 = new WorkStatus(
954                work2.getId(),
955                BLOCKED,
956                Data.EMPTY,
957                Collections.<String>emptyList());
958        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1, workStatus2));
959
960        workSpecDao.setState(ENQUEUED, work0.getStringId());
961
962        verify(mockObserver, times(2)).onChanged(captor.capture());
963        assertThat(captor.getValue(), is(not(nullValue())));
964        assertThat(captor.getValue().size(), is(3));
965
966        workStatus0 = new WorkStatus(
967                work0.getId(),
968                ENQUEUED,
969                Data.EMPTY,
970                Collections.<String>emptyList());
971        assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1, workStatus2));
972
973        liveData.removeObservers(testLifecycleOwner);
974    }
975
976    @Test
977    @SmallTest
978    public void testCancelWorkById() {
979        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
980
981        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
982        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
983        insertWorkSpecAndTags(work0);
984        insertWorkSpecAndTags(work1);
985
986        mWorkManagerImpl.synchronous().cancelWorkByIdSync(work0.getId());
987        assertThat(workSpecDao.getState(work0.getStringId()), is(CANCELLED));
988        assertThat(workSpecDao.getState(work1.getStringId()), is(not(CANCELLED)));
989    }
990
991    @Test
992    @SmallTest
993    public void testCancelWorkById_cancelsDependentWork() {
994        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
995
996        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
997        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
998                .setInitialState(BLOCKED)
999                .build();
1000        insertWorkSpecAndTags(work0);
1001        insertWorkSpecAndTags(work1);
1002        insertDependency(work1, work0);
1003
1004        mWorkManagerImpl.synchronous().cancelWorkByIdSync(work0.getId());
1005
1006        assertThat(workSpecDao.getState(work0.getStringId()), is(CANCELLED));
1007        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1008    }
1009
1010    @Test
1011    @SmallTest
1012    public void testCancelWorkById_cancelsUnfinishedWorkOnly() {
1013        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1014
1015        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
1016                .setInitialState(SUCCEEDED)
1017                .build();
1018        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
1019                .setInitialState(ENQUEUED)
1020                .build();
1021        insertWorkSpecAndTags(work0);
1022        insertWorkSpecAndTags(work1);
1023        insertDependency(work1, work0);
1024
1025        mWorkManagerImpl.synchronous().cancelWorkByIdSync(work0.getId());
1026
1027        assertThat(workSpecDao.getState(work0.getStringId()), is(SUCCEEDED));
1028        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1029    }
1030
1031    @Test
1032    @SmallTest
1033    public void testCancelAllWorkByTag() {
1034        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1035
1036        final String tagToClear = "tag_to_clear";
1037        final String tagNotToClear = "tag_not_to_clear";
1038
1039        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
1040                .addTag(tagToClear)
1041                .build();
1042        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
1043                .addTag(tagToClear)
1044                .build();
1045        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
1046                .addTag(tagNotToClear)
1047                .build();
1048        OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(TestWorker.class)
1049                .addTag(tagNotToClear)
1050                .build();
1051        insertWorkSpecAndTags(work0);
1052        insertWorkSpecAndTags(work1);
1053        insertWorkSpecAndTags(work2);
1054        insertWorkSpecAndTags(work3);
1055
1056        mWorkManagerImpl.synchronous().cancelAllWorkByTagSync(tagToClear);
1057
1058        assertThat(workSpecDao.getState(work0.getStringId()), is(CANCELLED));
1059        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1060        assertThat(workSpecDao.getState(work2.getStringId()), is(not(CANCELLED)));
1061        assertThat(workSpecDao.getState(work3.getStringId()), is(not(CANCELLED)));
1062    }
1063
1064    @Test
1065    @SmallTest
1066    public void testCancelAllWorkByTag_cancelsDependentWork() {
1067        String tag = "tag";
1068
1069        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
1070                .addTag(tag)
1071                .build();
1072
1073        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1074        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1075        OneTimeWorkRequest work3 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1076        OneTimeWorkRequest work4 = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1077
1078        insertWorkSpecAndTags(work0);
1079        insertWorkSpecAndTags(work1);
1080        insertWorkSpecAndTags(work2);
1081        insertWorkSpecAndTags(work3);
1082        insertWorkSpecAndTags(work4);
1083
1084        // Dependency graph:
1085        //                             0
1086        //                             |
1087        //                       |------------|
1088        //            3          1            4
1089        //            |          |
1090        //            ------------
1091        //                 |
1092        //                 2
1093
1094        insertDependency(work2, work1);
1095        insertDependency(work2, work3);
1096        insertDependency(work1, work0);
1097        insertDependency(work4, work0);
1098
1099        mWorkManagerImpl.synchronous().cancelAllWorkByTagSync(tag);
1100
1101        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1102        assertThat(workSpecDao.getState(work0.getStringId()), is(CANCELLED));
1103        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1104        assertThat(workSpecDao.getState(work2.getStringId()), is(CANCELLED));
1105        assertThat(workSpecDao.getState(work3.getStringId()), is(not(CANCELLED)));
1106        assertThat(workSpecDao.getState(work4.getStringId()), is(CANCELLED));
1107    }
1108
1109    @Test
1110    @SmallTest
1111    public void testCancelWorkByName() {
1112        final String testName = "myname";
1113
1114        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
1115        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
1116        insertNamedWorks(testName, work0, work1);
1117
1118        mWorkManagerImpl.synchronous().cancelUniqueWorkSync(testName);
1119
1120        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1121        assertThat(workSpecDao.getState(work0.getStringId()), is(CANCELLED));
1122        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1123    }
1124
1125    @Test
1126    @LargeTest
1127    public void testCancelWorkByName_ignoresFinishedWork() {
1128        final String testName = "myname";
1129
1130        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
1131                .setInitialState(SUCCEEDED)
1132                .build();
1133        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class).build();
1134        insertNamedWorks(testName, work0, work1);
1135
1136        mWorkManagerImpl.synchronous().cancelUniqueWorkSync(testName);
1137
1138        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1139        assertThat(workSpecDao.getState(work0.getStringId()), is(SUCCEEDED));
1140        assertThat(workSpecDao.getState(work1.getStringId()), is(CANCELLED));
1141    }
1142
1143    @Test
1144    @SmallTest
1145    public void testSynchronousCancelAndGetStatus() {
1146        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1147        insertWorkSpecAndTags(work);
1148
1149        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1150        assertThat(workSpecDao.getState(work.getStringId()), is(ENQUEUED));
1151
1152        mWorkManagerImpl.synchronous().cancelWorkByIdSync(work.getId());
1153        assertThat(mWorkManagerImpl.getStatusByIdSync(work.getId()).getState(), is(CANCELLED));
1154    }
1155
1156    @Test
1157    @SmallTest
1158    public void testGenerateCleanupCallback_resetsRunningWorkStatuses() {
1159        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1160
1161        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1162                .setInitialState(RUNNING)
1163                .build();
1164        workSpecDao.insertWorkSpec(work.getWorkSpec());
1165
1166        assertThat(workSpecDao.getState(work.getStringId()), is(RUNNING));
1167
1168        SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper();
1169        SupportSQLiteDatabase db = openHelper.getWritableDatabase();
1170        WorkDatabase.generateCleanupCallback().onOpen(db);
1171
1172        assertThat(workSpecDao.getState(work.getStringId()), is(ENQUEUED));
1173    }
1174
1175    @Test
1176    @SmallTest
1177    public void testGenerateCleanupCallback_deletesOldFinishedWork() {
1178        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
1179                .setInitialState(SUCCEEDED)
1180                .setPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS)
1181                .build();
1182        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
1183                .setPeriodStartTime(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
1184                .build();
1185
1186        insertWorkSpecAndTags(work1);
1187        insertWorkSpecAndTags(work2);
1188
1189        SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper();
1190        SupportSQLiteDatabase db = openHelper.getWritableDatabase();
1191        WorkDatabase.generateCleanupCallback().onOpen(db);
1192
1193        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1194        assertThat(workSpecDao.getWorkSpec(work1.getStringId()), is(nullValue()));
1195        assertThat(workSpecDao.getWorkSpec(work2.getStringId()), is(not(nullValue())));
1196    }
1197
1198    @Test
1199    @SmallTest
1200    public void testGenerateCleanupCallback_doesNotDeleteOldFinishedWorkWithActiveDependents() {
1201        OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
1202                .setInitialState(SUCCEEDED)
1203                .setPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS)
1204                .build();
1205        OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
1206                .setInitialState(SUCCEEDED)
1207                .setPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS)
1208                .build();
1209        OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
1210                .setInitialState(ENQUEUED)
1211                .setPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS)
1212                .build();
1213
1214        insertWorkSpecAndTags(work0);
1215        insertWorkSpecAndTags(work1);
1216        insertWorkSpecAndTags(work2);
1217
1218        // Dependency graph: 0 -> 1 -> 2
1219        insertDependency(work1, work0);
1220        insertDependency(work2, work1);
1221
1222        SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper();
1223        SupportSQLiteDatabase db = openHelper.getWritableDatabase();
1224        WorkDatabase.generateCleanupCallback().onOpen(db);
1225
1226        WorkSpecDao workSpecDao = mDatabase.workSpecDao();
1227        assertThat(workSpecDao.getWorkSpec(work0.getStringId()), is(nullValue()));
1228        assertThat(workSpecDao.getWorkSpec(work1.getStringId()), is(not(nullValue())));
1229        assertThat(workSpecDao.getWorkSpec(work2.getStringId()), is(not(nullValue())));
1230    }
1231
1232    @Test
1233    @SmallTest
1234    @SdkSuppress(maxSdkVersion = 22)
1235    public void testEnqueueApi22OrLower_withBatteryNotLowConstraint_expectsOriginalWorker() {
1236        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1237                .setConstraints(new Constraints.Builder()
1238                        .setRequiresBatteryNotLow(true)
1239                        .build())
1240                .build();
1241        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1242
1243        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1244        assertThat(workSpec.workerClassName, is(TestWorker.class.getName()));
1245    }
1246
1247    @Test
1248    @SmallTest
1249    @SdkSuppress(maxSdkVersion = 22)
1250    public void testEnqueueApi22OrLower_withStorageNotLowConstraint_expectsOriginalWorker() {
1251        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1252                .setConstraints(new Constraints.Builder()
1253                        .setRequiresStorageNotLow(true)
1254                        .build())
1255                .build();
1256        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1257
1258        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1259        assertThat(workSpec.workerClassName, is(TestWorker.class.getName()));
1260    }
1261
1262    @Test
1263    @SmallTest
1264    @SdkSuppress(minSdkVersion = 23, maxSdkVersion = 25)
1265    public void testEnqueueApi23To25_withBatteryNotLowConstraint_expectsConstraintTrackingWorker() {
1266        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1267                .setConstraints(new Constraints.Builder()
1268                .setRequiresBatteryNotLow(true)
1269                .build())
1270                .build();
1271        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1272
1273        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1274        assertThat(workSpec.workerClassName, is(ConstraintTrackingWorker.class.getName()));
1275        assertThat(workSpec.input.getString(
1276                ConstraintTrackingWorker.ARGUMENT_CLASS_NAME, null),
1277                is(TestWorker.class.getName()));
1278    }
1279
1280    @Test
1281    @SmallTest
1282    @SdkSuppress(minSdkVersion = 23, maxSdkVersion = 25)
1283    public void testEnqueueApi23To25_withStorageNotLowConstraint_expectsConstraintTrackingWorker() {
1284        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1285                .setConstraints(new Constraints.Builder()
1286                        .setRequiresStorageNotLow(true)
1287                        .build())
1288                .build();
1289        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1290
1291        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1292        assertThat(workSpec.workerClassName, is(ConstraintTrackingWorker.class.getName()));
1293        assertThat(workSpec.input.getString(
1294                ConstraintTrackingWorker.ARGUMENT_CLASS_NAME, null),
1295                is(TestWorker.class.getName()));
1296    }
1297
1298    @Test
1299    @SmallTest
1300    @SdkSuppress(minSdkVersion = 26)
1301    public void testEnqueueApi26OrHigher_withBatteryNotLowConstraint_expectsOriginalWorker() {
1302        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1303                .setConstraints(new Constraints.Builder()
1304                        .setRequiresBatteryNotLow(true)
1305                        .build())
1306                .build();
1307        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1308
1309        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1310        assertThat(workSpec.workerClassName, is(TestWorker.class.getName()));
1311    }
1312
1313    @Test
1314    @SmallTest
1315    @SdkSuppress(minSdkVersion = 26)
1316    public void testEnqueueApi26OrHigher_withStorageNotLowConstraint_expectsOriginalWorker() {
1317        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
1318                .setConstraints(new Constraints.Builder()
1319                        .setRequiresStorageNotLow(true)
1320                        .build())
1321                .build();
1322        mWorkManagerImpl.beginWith(work).synchronous().enqueueSync();
1323
1324        WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
1325        assertThat(workSpec.workerClassName, is(TestWorker.class.getName()));
1326    }
1327
1328    private void insertWorkSpecAndTags(OneTimeWorkRequest work) {
1329        mDatabase.workSpecDao().insertWorkSpec(work.getWorkSpec());
1330        for (String tag : work.getTags()) {
1331            mDatabase.workTagDao().insert(new WorkTag(tag, work.getStringId()));
1332        }
1333    }
1334
1335    private void insertNamedWorks(String name, OneTimeWorkRequest... works) {
1336        for (OneTimeWorkRequest work : works) {
1337            insertWorkSpecAndTags(work);
1338            mDatabase.workNameDao().insert(new WorkName(name, work.getStringId()));
1339        }
1340    }
1341
1342    private void insertDependency(OneTimeWorkRequest work, OneTimeWorkRequest prerequisiteWork) {
1343        mDatabase.dependencyDao().insertDependency(
1344                new Dependency(work.getStringId(), prerequisiteWork.getStringId()));
1345    }
1346}
1347