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