WorkerWrapperTest.java revision dcbf20db18e3e93a13e9fa75fa4b723255b87c54
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.State.BLOCKED;
20import static androidx.work.State.CANCELLED;
21import static androidx.work.State.ENQUEUED;
22import static androidx.work.State.FAILED;
23import static androidx.work.State.RUNNING;
24import static androidx.work.State.SUCCEEDED;
25
26import static org.hamcrest.CoreMatchers.equalTo;
27import static org.hamcrest.CoreMatchers.is;
28import static org.hamcrest.CoreMatchers.notNullValue;
29import static org.hamcrest.MatcherAssert.assertThat;
30import static org.hamcrest.Matchers.contains;
31import static org.hamcrest.Matchers.containsInAnyOrder;
32import static org.hamcrest.Matchers.greaterThan;
33import static org.mockito.Mockito.mock;
34import static org.mockito.Mockito.spy;
35import static org.mockito.Mockito.times;
36import static org.mockito.Mockito.verify;
37
38import android.content.Context;
39import android.support.test.InstrumentationRegistry;
40import android.support.test.filters.LargeTest;
41import android.support.test.filters.SmallTest;
42import android.support.test.runner.AndroidJUnit4;
43
44import androidx.work.ArrayCreatingInputMerger;
45import androidx.work.Data;
46import androidx.work.DatabaseTest;
47import androidx.work.PeriodicWorkRequest;
48import androidx.work.WorkRequest;
49import androidx.work.Worker;
50import androidx.work.impl.model.Dependency;
51import androidx.work.impl.model.DependencyDao;
52import androidx.work.impl.model.WorkSpec;
53import androidx.work.impl.model.WorkSpecDao;
54import androidx.work.impl.utils.taskexecutor.InstantTaskExecutorRule;
55import androidx.work.worker.ChainedArgumentWorker;
56import androidx.work.worker.EchoingWorker;
57import androidx.work.worker.FailureWorker;
58import androidx.work.worker.RetryWorker;
59import androidx.work.worker.SleepTestWorker;
60import androidx.work.worker.TestWorker;
61
62import org.junit.Before;
63import org.junit.Rule;
64import org.junit.Test;
65import org.junit.runner.RunWith;
66import org.mockito.ArgumentCaptor;
67
68import java.util.Arrays;
69import java.util.Collections;
70import java.util.List;
71import java.util.concurrent.Executors;
72import java.util.concurrent.TimeUnit;
73
74@RunWith(AndroidJUnit4.class)
75public class WorkerWrapperTest extends DatabaseTest {
76    private WorkSpecDao mWorkSpecDao;
77    private DependencyDao mDependencyDao;
78    private Context mContext;
79    private ExecutionListener mMockListener;
80    private Scheduler mMockScheduler;
81
82    @Rule
83    public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule();
84
85    @Before
86    public void setUp() {
87        mContext = InstrumentationRegistry.getTargetContext();
88        mWorkSpecDao = spy(mDatabase.workSpecDao());
89        mDependencyDao = mDatabase.dependencyDao();
90        mMockListener = mock(ExecutionListener.class);
91        mMockScheduler = mock(Scheduler.class);
92    }
93
94    @Test
95    @SmallTest
96    public void testSuccess() {
97        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
98        insertWork(work);
99        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
100                .withListener(mMockListener)
101                .build()
102                .run();
103        verify(mMockListener).onExecuted(work.getId(), true, false);
104        assertThat(mWorkSpecDao.getState(work.getId()), is(SUCCEEDED));
105    }
106
107    @Test
108    @SmallTest
109    public void testRunAttemptCountIncremented_successfulExecution() {
110        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
111        insertWork(work);
112        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
113                .withSchedulers(Collections.singletonList(mMockScheduler))
114                .withListener(mMockListener)
115                .build()
116                .run();
117        WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getId());
118        assertThat(latestWorkSpec.runAttemptCount, is(1));
119    }
120
121    @Test
122    @SmallTest
123    public void testRunAttemptCountIncremented_failedExecution() {
124        WorkRequest work = new WorkRequest.Builder(FailureWorker.class).build();
125        insertWork(work);
126        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
127                .withSchedulers(Collections.singletonList(mMockScheduler))
128                .withListener(mMockListener)
129                .build()
130                .run();
131        WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getId());
132        assertThat(latestWorkSpec.runAttemptCount, is(1));
133    }
134
135    @Test
136    @SmallTest
137    public void testPermanentErrorWithInvalidWorkSpecId() {
138        final String invalidWorkSpecId = "INVALID_ID";
139        new WorkerWrapper.Builder(mContext, mDatabase, invalidWorkSpecId)
140                .withListener(mMockListener)
141                .build()
142                .run();
143        verify(mMockListener).onExecuted(invalidWorkSpecId, false, false);
144    }
145
146    @Test
147    @SmallTest
148    public void testNotEnqueued() {
149        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
150                .withInitialState(RUNNING)
151                .build();
152        insertWork(work);
153        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
154                .withListener(mMockListener)
155                .build()
156                .run();
157        verify(mMockListener).onExecuted(work.getId(), false, true);
158    }
159
160    @Test
161    @SmallTest
162    public void testCancelled() {
163        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
164                .withInitialState(CANCELLED)
165                .build();
166        insertWork(work);
167        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
168                .withListener(mMockListener)
169                .build()
170                .run();
171        verify(mMockListener).onExecuted(work.getId(), false, false);
172        assertThat(mWorkSpecDao.getState(work.getId()), is(CANCELLED));
173    }
174
175    @Test
176    @SmallTest
177    public void testPermanentErrorWithInvalidWorkerClass() {
178        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
179        getWorkSpec(work).workerClassName = "INVALID_CLASS_NAME";
180        insertWork(work);
181        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
182                .withListener(mMockListener)
183                .build()
184                .run();
185        verify(mMockListener).onExecuted(work.getId(), false, false);
186        assertThat(mWorkSpecDao.getState(work.getId()), is(FAILED));
187    }
188
189    @Test
190    @SmallTest
191    public void testPermanentErrorWithInvalidInputMergerClass() {
192        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
193        getWorkSpec(work).inputMergerClassName = "INVALID_CLASS_NAME";
194        insertWork(work);
195        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
196                .withSchedulers(Collections.singletonList(mMockScheduler))
197                .withListener(mMockListener)
198                .build()
199                .run();
200        verify(mMockListener).onExecuted(work.getId(), false, false);
201        assertThat(mWorkSpecDao.getState(work.getId()), is(FAILED));
202    }
203
204    @Test
205    @SmallTest
206    public void testFailed() {
207        WorkRequest work = new WorkRequest.Builder(FailureWorker.class).build();
208        insertWork(work);
209        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
210                .withListener(mMockListener)
211                .build()
212                .run();
213        verify(mMockListener).onExecuted(work.getId(), false, false);
214        assertThat(mWorkSpecDao.getState(work.getId()), is(FAILED));
215    }
216
217    @Test
218    @LargeTest
219    public void testRunning() throws InterruptedException {
220        WorkRequest work = new WorkRequest.Builder(SleepTestWorker.class).build();
221        insertWork(work);
222        WorkerWrapper wrapper = new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
223                .withListener(mMockListener)
224                .build();
225        Executors.newSingleThreadExecutor().submit(wrapper);
226        Thread.sleep(2000L); // Async wait duration.
227        assertThat(mWorkSpecDao.getState(work.getId()), is(RUNNING));
228        Thread.sleep(SleepTestWorker.SLEEP_DURATION);
229        verify(mMockListener).onExecuted(work.getId(), true, false);
230    }
231
232    @Test
233    @SmallTest
234    public void testRunning_onlyWhenEnqueued() {
235        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
236                .withInitialState(RUNNING)
237                .build();
238        insertWork(work);
239        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
240                .withListener(mMockListener)
241                .build()
242                .run();
243        verify(mMockListener).onExecuted(work.getId(), false, true);
244    }
245
246    @Test
247    @SmallTest
248    public void testDependencies() {
249        WorkRequest prerequisiteWork = new WorkRequest.Builder(TestWorker.class).build();
250        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
251                .withInitialState(BLOCKED).build();
252        Dependency dependency = new Dependency(work.getId(), prerequisiteWork.getId());
253
254        mDatabase.beginTransaction();
255        try {
256            insertWork(prerequisiteWork);
257            insertWork(work);
258            mDependencyDao.insertDependency(dependency);
259            mDatabase.setTransactionSuccessful();
260        } finally {
261            mDatabase.endTransaction();
262        }
263
264        assertThat(mWorkSpecDao.getState(prerequisiteWork.getId()), is(ENQUEUED));
265        assertThat(mWorkSpecDao.getState(work.getId()), is(BLOCKED));
266        assertThat(mDependencyDao.hasCompletedAllPrerequisites(work.getId()), is(false));
267
268        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getId())
269                .withListener(mMockListener)
270                .withSchedulers(Collections.singletonList(mMockScheduler))
271                .build()
272                .run();
273
274        assertThat(mWorkSpecDao.getState(prerequisiteWork.getId()), is(SUCCEEDED));
275        assertThat(mWorkSpecDao.getState(work.getId()), is(ENQUEUED));
276        assertThat(mDependencyDao.hasCompletedAllPrerequisites(work.getId()), is(true));
277
278        ArgumentCaptor<WorkSpec> captor = ArgumentCaptor.forClass(WorkSpec.class);
279        verify(mMockScheduler).schedule(captor.capture());
280        assertThat(captor.getValue().id, is(work.getId()));
281    }
282
283    @Test
284    @SmallTest
285    public void testDependencies_passesOutputs() {
286        WorkRequest prerequisiteWork = new WorkRequest.Builder(ChainedArgumentWorker.class).build();
287        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
288                .withInitialState(BLOCKED)
289                .build();
290        Dependency dependency = new Dependency(work.getId(), prerequisiteWork.getId());
291
292        mDatabase.beginTransaction();
293        try {
294            insertWork(prerequisiteWork);
295            insertWork(work);
296            mDependencyDao.insertDependency(dependency);
297            mDatabase.setTransactionSuccessful();
298        } finally {
299            mDatabase.endTransaction();
300        }
301
302        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getId())
303                .withSchedulers(Collections.singletonList(mMockScheduler))
304                .build().run();
305
306        List<Data> arguments = mWorkSpecDao.getInputsFromPrerequisites(work.getId());
307        assertThat(arguments.size(), is(1));
308        assertThat(arguments, contains(ChainedArgumentWorker.getChainedArguments()));
309    }
310
311    @Test
312    @SmallTest
313    public void testDependencies_passesMergedOutputs() {
314        String key = "key";
315        String value1 = "value1";
316        String value2 = "value2";
317
318        WorkRequest prerequisiteWork1 = new WorkRequest.Builder(EchoingWorker.class)
319                .withInputData(new Data.Builder().putString(key, value1).build())
320                .build();
321        WorkRequest prerequisiteWork2 = new WorkRequest.Builder(EchoingWorker.class)
322                .withInputData(new Data.Builder().putString(key, value2).build())
323                .build();
324        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
325                .withInputMerger(ArrayCreatingInputMerger.class)
326                .build();
327        Dependency dependency1 = new Dependency(work.getId(), prerequisiteWork1.getId());
328        Dependency dependency2 = new Dependency(work.getId(), prerequisiteWork2.getId());
329
330        mDatabase.beginTransaction();
331        try {
332            insertWork(prerequisiteWork1);
333            insertWork(prerequisiteWork2);
334            insertWork(work);
335            mDependencyDao.insertDependency(dependency1);
336            mDependencyDao.insertDependency(dependency2);
337            mDatabase.setTransactionSuccessful();
338        } finally {
339            mDatabase.endTransaction();
340        }
341
342        // Run the prerequisites.
343        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork1.getId())
344                .withSchedulers(Collections.singletonList(mMockScheduler))
345                .build().run();
346
347        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork2.getId())
348                .withSchedulers(Collections.singletonList(mMockScheduler))
349                .build().run();
350
351        // Create and run the dependent work.
352        WorkerWrapper workerWrapper = new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
353                .withSchedulers(Collections.singletonList(mMockScheduler))
354                .build();
355        workerWrapper.run();
356
357        Data input = workerWrapper.mWorker.getInputData();
358        assertThat(input.size(), is(1));
359        assertThat(Arrays.asList(input.getStringArray(key)),
360                containsInAnyOrder(value1, value2));
361    }
362
363    @Test
364    @SmallTest
365    public void testDependencies_setsPeriodStartTimesForUnblockedWork() {
366        WorkRequest prerequisiteWork = new WorkRequest.Builder(TestWorker.class).build();
367        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
368                .withInitialState(BLOCKED)
369                .build();
370        Dependency dependency = new Dependency(work.getId(), prerequisiteWork.getId());
371
372        mDatabase.beginTransaction();
373        try {
374            insertWork(prerequisiteWork);
375            insertWork(work);
376            mDependencyDao.insertDependency(dependency);
377            mDatabase.setTransactionSuccessful();
378        } finally {
379            mDatabase.endTransaction();
380        }
381
382        long beforeUnblockedTime = System.currentTimeMillis();
383
384        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getId())
385                .withListener(mMockListener)
386                .withSchedulers(Collections.singletonList(mMockScheduler))
387                .build()
388                .run();
389
390        WorkSpec workSpec = mWorkSpecDao.getWorkSpec(work.getId());
391        assertThat(workSpec.periodStartTime, is(greaterThan(beforeUnblockedTime)));
392    }
393
394    @Test
395    @SmallTest
396    public void testDependencies_failsUncancelledDependentsOnFailure() {
397        WorkRequest prerequisiteWork = new WorkRequest.Builder(FailureWorker.class).build();
398        WorkRequest work = new WorkRequest.Builder(TestWorker.class)
399                .withInitialState(BLOCKED)
400                .build();
401        WorkRequest cancelledWork = new WorkRequest.Builder(TestWorker.class)
402                .withInitialState(CANCELLED)
403                .build();
404        Dependency dependency1 = new Dependency(work.getId(), prerequisiteWork.getId());
405        Dependency dependency2 = new Dependency(cancelledWork.getId(), prerequisiteWork.getId());
406
407        mDatabase.beginTransaction();
408        try {
409            insertWork(prerequisiteWork);
410            insertWork(work);
411            insertWork(cancelledWork);
412            mDependencyDao.insertDependency(dependency1);
413            mDependencyDao.insertDependency(dependency2);
414            mDatabase.setTransactionSuccessful();
415        } finally {
416            mDatabase.endTransaction();
417        }
418
419        new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getId()).build().run();
420
421        assertThat(mWorkSpecDao.getState(prerequisiteWork.getId()), is(FAILED));
422        assertThat(mWorkSpecDao.getState(work.getId()), is(FAILED));
423        assertThat(mWorkSpecDao.getState(cancelledWork.getId()), is(CANCELLED));
424    }
425
426    @Test
427    @SmallTest
428    public void testRun_periodicWork_success_updatesPeriodStartTime() {
429        long intervalDuration = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
430        long periodStartTime = System.currentTimeMillis();
431        long expectedNextPeriodStartTime = periodStartTime + intervalDuration;
432
433        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
434                TestWorker.class, intervalDuration, TimeUnit.MILLISECONDS).build();
435
436        getWorkSpec(periodicWork).periodStartTime = periodStartTime;
437
438        insertWork(periodicWork);
439
440        new WorkerWrapper.Builder(mContext, mDatabase, periodicWork.getId())
441                .withListener(mMockListener)
442                .build()
443                .run();
444
445        WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getId());
446        assertThat(updatedWorkSpec.periodStartTime, is(expectedNextPeriodStartTime));
447    }
448
449    @Test
450    @SmallTest
451    public void testRun_periodicWork_failure_updatesPeriodStartTime() {
452        long intervalDuration = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
453        long periodStartTime = System.currentTimeMillis();
454        long expectedNextPeriodStartTime = periodStartTime + intervalDuration;
455
456        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
457                FailureWorker.class, intervalDuration, TimeUnit.MILLISECONDS).build();
458
459        getWorkSpec(periodicWork).periodStartTime = periodStartTime;
460
461        insertWork(periodicWork);
462
463        new WorkerWrapper.Builder(mContext, mDatabase, periodicWork.getId())
464                .withListener(mMockListener)
465                .build()
466                .run();
467
468        WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getId());
469        assertThat(updatedWorkSpec.periodStartTime, is(expectedNextPeriodStartTime));
470    }
471
472    @Test
473    @SmallTest
474    public void testPeriodicWork_success() {
475        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
476                TestWorker.class,
477                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
478                TimeUnit.MILLISECONDS)
479                .build();
480
481        final String periodicWorkId = periodicWork.getId();
482        insertWork(periodicWork);
483        new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
484                .withListener(mMockListener)
485                .build()
486                .run();
487
488        WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
489        verify(mMockListener).onExecuted(periodicWorkId, true, false);
490        assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
491        assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
492    }
493
494    @Test
495    @SmallTest
496    public void testPeriodicWork_fail() {
497        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
498                FailureWorker.class,
499                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
500                TimeUnit.MILLISECONDS)
501                .build();
502
503        final String periodicWorkId = periodicWork.getId();
504        insertWork(periodicWork);
505        new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
506                .withListener(mMockListener)
507                .build()
508                .run();
509
510        WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
511        verify(mMockListener).onExecuted(periodicWorkId, false, false);
512        assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
513        assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
514    }
515
516    @Test
517    @SmallTest
518    public void testPeriodicWork_retry() {
519        PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
520                RetryWorker.class,
521                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
522                TimeUnit.MILLISECONDS)
523                .build();
524
525        final String periodicWorkId = periodicWork.getId();
526        insertWork(periodicWork);
527        new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
528                .withListener(mMockListener)
529                .build()
530                .run();
531
532        WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
533        verify(mMockListener).onExecuted(periodicWorkId, false, true);
534        assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(1));
535        assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
536    }
537
538    @Test
539    @SmallTest
540    public void testScheduler() {
541        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
542        insertWork(work);
543        Scheduler mockScheduler = mock(Scheduler.class);
544
545        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
546                .withSchedulers(Collections.singletonList(mockScheduler))
547                .build()
548                .run();
549
550        verify(mockScheduler).schedule();
551    }
552
553    @Test
554    @SmallTest
555    public void testFromWorkSpec_hasAppContext() {
556        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
557        Worker worker = WorkerWrapper.workerFromWorkSpec(
558                mContext,
559                getWorkSpec(work),
560                Data.EMPTY,
561                null);
562
563        assertThat(worker, is(notNullValue()));
564        assertThat(worker.getAppContext(), is(equalTo(mContext.getApplicationContext())));
565    }
566
567    @Test
568    @SmallTest
569    public void testFromWorkSpec_hasCorrectArguments() {
570        String key = "KEY";
571        String expectedValue = "VALUE";
572        Data input = new Data.Builder().putString(key, expectedValue).build();
573
574        WorkRequest work = new WorkRequest.Builder(TestWorker.class).withInputData(input).build();
575        Worker worker = WorkerWrapper.workerFromWorkSpec(
576                mContext,
577                getWorkSpec(work),
578                input,
579                null);
580
581        assertThat(worker, is(notNullValue()));
582        assertThat(worker.getInputData().getString(key, null), is(expectedValue));
583
584        work = new WorkRequest.Builder(TestWorker.class).build();
585        worker = WorkerWrapper.workerFromWorkSpec(
586                mContext,
587                getWorkSpec(work),
588                Data.EMPTY,
589                null);
590
591        assertThat(worker, is(notNullValue()));
592        assertThat(worker.getInputData().size(), is(0));
593    }
594
595    @Test
596    @SmallTest
597    public void testSuccess_withPendingScheduledWork() {
598        WorkRequest work = new WorkRequest.Builder(TestWorker.class).build();
599        insertWork(work);
600
601        WorkRequest unscheduled = new WorkRequest.Builder(TestWorker.class).build();
602        insertWork(unscheduled);
603
604        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
605                .withSchedulers(Collections.singletonList(mMockScheduler))
606                .withListener(mMockListener)
607                .build()
608                .run();
609
610        verify(mMockScheduler, times(1)).schedule(unscheduled.getWorkSpec());
611        verify(mMockListener).onExecuted(work.getId(), true, false);
612        assertThat(mWorkSpecDao.getState(work.getId()), is(SUCCEEDED));
613    }
614
615    @Test
616    @SmallTest
617    public void testFailure_withPendingScheduledWork() {
618        WorkRequest work = new WorkRequest.Builder(FailureWorker.class).build();
619        insertWork(work);
620
621        WorkRequest unscheduled = new WorkRequest.Builder(TestWorker.class).build();
622        insertWork(unscheduled);
623
624        new WorkerWrapper.Builder(mContext, mDatabase, work.getId())
625                .withSchedulers(Collections.singletonList(mMockScheduler))
626                .withListener(mMockListener)
627                .build()
628                .run();
629
630        verify(mMockScheduler, times(1)).schedule(unscheduled.getWorkSpec());
631        verify(mMockListener).onExecuted(work.getId(), false, false);
632        assertThat(mWorkSpecDao.getState(work.getId()), is(FAILED));
633    }
634}
635