blob: 4a50d10965b9fb32a955f6fdc61b64b19e24f90f [file] [log] [blame]
/*
* Copyright 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.work.impl;
import static androidx.work.State.BLOCKED;
import static androidx.work.State.CANCELLED;
import static androidx.work.State.ENQUEUED;
import static androidx.work.State.FAILED;
import static androidx.work.State.RUNNING;
import static androidx.work.State.SUCCEEDED;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.greaterThan;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import androidx.work.ArrayCreatingInputMerger;
import androidx.work.Data;
import androidx.work.DatabaseTest;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.Worker;
import androidx.work.impl.model.Dependency;
import androidx.work.impl.model.DependencyDao;
import androidx.work.impl.model.WorkSpec;
import androidx.work.impl.model.WorkSpecDao;
import androidx.work.impl.utils.taskexecutor.InstantTaskExecutorRule;
import androidx.work.worker.ChainedArgumentWorker;
import androidx.work.worker.EchoingWorker;
import androidx.work.worker.ExceptionWorker;
import androidx.work.worker.FailureWorker;
import androidx.work.worker.InfiniteTestWorker;
import androidx.work.worker.InterruptionAwareWorker;
import androidx.work.worker.RetryWorker;
import androidx.work.worker.SleepTestWorker;
import androidx.work.worker.TestWorker;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class WorkerWrapperTest extends DatabaseTest {
private WorkSpecDao mWorkSpecDao;
private DependencyDao mDependencyDao;
private Context mContext;
private ExecutionListener mMockListener;
private Scheduler mMockScheduler;
@Rule
public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule();
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mWorkSpecDao = spy(mDatabase.workSpecDao());
mDependencyDao = mDatabase.dependencyDao();
mMockListener = mock(ExecutionListener.class);
mMockScheduler = mock(Scheduler.class);
}
@Test
@SmallTest
public void testSuccess() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), true, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(SUCCEEDED));
}
@Test
@SmallTest
public void testRunAttemptCountIncremented_successfulExecution() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
assertThat(latestWorkSpec.runAttemptCount, is(1));
}
@Test
@SmallTest
public void testRunAttemptCountIncremented_failedExecution() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
assertThat(latestWorkSpec.runAttemptCount, is(1));
}
@Test
@SmallTest
public void testPermanentErrorWithInvalidWorkSpecId() {
final String invalidWorkSpecId = "INVALID_ID";
new WorkerWrapper.Builder(mContext, mDatabase, invalidWorkSpecId)
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(invalidWorkSpecId, false, false);
}
@Test
@SmallTest
public void testNotEnqueued() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(RUNNING)
.build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, true);
}
@Test
@SmallTest
public void testCancelled() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(CANCELLED)
.build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(CANCELLED));
}
@Test
@SmallTest
public void testPermanentErrorWithInvalidWorkerClass() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
getWorkSpec(work).workerClassName = "INVALID_CLASS_NAME";
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
}
@Test
@SmallTest
public void testPermanentErrorWithInvalidInputMergerClass() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
getWorkSpec(work).inputMergerClassName = "INVALID_CLASS_NAME";
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
}
@Test
@SmallTest
public void testFailed() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
}
@Test
@LargeTest
public void testRunning() throws InterruptedException {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(SleepTestWorker.class).build();
insertWork(work);
WorkerWrapper wrapper = new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build();
Executors.newSingleThreadExecutor().submit(wrapper);
Thread.sleep(2000L); // Async wait duration.
assertThat(mWorkSpecDao.getState(work.getStringId()), is(RUNNING));
Thread.sleep(SleepTestWorker.SLEEP_DURATION);
verify(mMockListener).onExecuted(work.getStringId(), true, false);
}
@Test
@SmallTest
public void testRunning_onlyWhenEnqueued() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(RUNNING)
.build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withListener(mMockListener)
.build()
.run();
verify(mMockListener).onExecuted(work.getStringId(), false, true);
}
@Test
@SmallTest
public void testDependencies() {
OneTimeWorkRequest prerequisiteWork =
new OneTimeWorkRequest.Builder(TestWorker.class).build();
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(BLOCKED).build();
Dependency dependency = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
mDatabase.beginTransaction();
try {
insertWork(prerequisiteWork);
insertWork(work);
mDependencyDao.insertDependency(dependency);
mDatabase.setTransactionSuccessful();
} finally {
mDatabase.endTransaction();
}
assertThat(mWorkSpecDao.getState(prerequisiteWork.getStringId()), is(ENQUEUED));
assertThat(mWorkSpecDao.getState(work.getStringId()), is(BLOCKED));
assertThat(mDependencyDao.hasCompletedAllPrerequisites(work.getStringId()), is(false));
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getStringId())
.withListener(mMockListener)
.withSchedulers(Collections.singletonList(mMockScheduler))
.build()
.run();
assertThat(mWorkSpecDao.getState(prerequisiteWork.getStringId()), is(SUCCEEDED));
assertThat(mWorkSpecDao.getState(work.getStringId()), is(ENQUEUED));
assertThat(mDependencyDao.hasCompletedAllPrerequisites(work.getStringId()), is(true));
ArgumentCaptor<WorkSpec> captor = ArgumentCaptor.forClass(WorkSpec.class);
verify(mMockScheduler).schedule(captor.capture());
assertThat(captor.getValue().id, is(work.getStringId()));
}
@Test
@SmallTest
public void testDependencies_passesOutputs() {
OneTimeWorkRequest prerequisiteWork =
new OneTimeWorkRequest.Builder(ChainedArgumentWorker.class).build();
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(BLOCKED)
.build();
Dependency dependency = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
mDatabase.beginTransaction();
try {
insertWork(prerequisiteWork);
insertWork(work);
mDependencyDao.insertDependency(dependency);
mDatabase.setTransactionSuccessful();
} finally {
mDatabase.endTransaction();
}
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.build().run();
List<Data> arguments = mWorkSpecDao.getInputsFromPrerequisites(work.getStringId());
assertThat(arguments.size(), is(1));
assertThat(arguments, contains(ChainedArgumentWorker.getChainedArguments()));
}
@Test
@SmallTest
public void testDependencies_passesMergedOutputs() {
String key = "key";
String value1 = "value1";
String value2 = "value2";
OneTimeWorkRequest prerequisiteWork1 = new OneTimeWorkRequest.Builder(EchoingWorker.class)
.setInputData(new Data.Builder().putString(key, value1).build())
.build();
OneTimeWorkRequest prerequisiteWork2 = new OneTimeWorkRequest.Builder(EchoingWorker.class)
.setInputData(new Data.Builder().putString(key, value2).build())
.build();
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInputMerger(ArrayCreatingInputMerger.class)
.build();
Dependency dependency1 =
new Dependency(work.getStringId(), prerequisiteWork1.getStringId());
Dependency dependency2 =
new Dependency(work.getStringId(), prerequisiteWork2.getStringId());
mDatabase.beginTransaction();
try {
insertWork(prerequisiteWork1);
insertWork(prerequisiteWork2);
insertWork(work);
mDependencyDao.insertDependency(dependency1);
mDependencyDao.insertDependency(dependency2);
mDatabase.setTransactionSuccessful();
} finally {
mDatabase.endTransaction();
}
// Run the prerequisites.
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork1.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.build().run();
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork2.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.build().run();
// Create and run the dependent work.
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.build();
workerWrapper.run();
Data input = workerWrapper.mWorker.getInputData();
assertThat(input.size(), is(1));
assertThat(Arrays.asList(input.getStringArray(key)),
containsInAnyOrder(value1, value2));
}
@Test
@SmallTest
public void testDependencies_setsPeriodStartTimesForUnblockedWork() {
OneTimeWorkRequest prerequisiteWork =
new OneTimeWorkRequest.Builder(TestWorker.class).build();
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(BLOCKED)
.build();
Dependency dependency = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
mDatabase.beginTransaction();
try {
insertWork(prerequisiteWork);
insertWork(work);
mDependencyDao.insertDependency(dependency);
mDatabase.setTransactionSuccessful();
} finally {
mDatabase.endTransaction();
}
long beforeUnblockedTime = System.currentTimeMillis();
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getStringId())
.withListener(mMockListener)
.withSchedulers(Collections.singletonList(mMockScheduler))
.build()
.run();
WorkSpec workSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
assertThat(workSpec.periodStartTime, is(greaterThan(beforeUnblockedTime)));
}
@Test
@SmallTest
public void testDependencies_failsUncancelledDependentsOnFailure() {
OneTimeWorkRequest prerequisiteWork =
new OneTimeWorkRequest.Builder(FailureWorker.class).build();
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(BLOCKED)
.build();
OneTimeWorkRequest cancelledWork = new OneTimeWorkRequest.Builder(TestWorker.class)
.setInitialState(CANCELLED)
.build();
Dependency dependency1 = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
Dependency dependency2 =
new Dependency(cancelledWork.getStringId(), prerequisiteWork.getStringId());
mDatabase.beginTransaction();
try {
insertWork(prerequisiteWork);
insertWork(work);
insertWork(cancelledWork);
mDependencyDao.insertDependency(dependency1);
mDependencyDao.insertDependency(dependency2);
mDatabase.setTransactionSuccessful();
} finally {
mDatabase.endTransaction();
}
new WorkerWrapper.Builder(mContext, mDatabase, prerequisiteWork.getStringId())
.build()
.run();
assertThat(mWorkSpecDao.getState(prerequisiteWork.getStringId()), is(FAILED));
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
assertThat(mWorkSpecDao.getState(cancelledWork.getStringId()), is(CANCELLED));
}
@Test
@SmallTest
public void testRun_periodicWork_success_updatesPeriodStartTime() {
long intervalDuration = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
long periodStartTime = System.currentTimeMillis();
long expectedNextPeriodStartTime = periodStartTime + intervalDuration;
PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
TestWorker.class, intervalDuration, TimeUnit.MILLISECONDS).build();
getWorkSpec(periodicWork).periodStartTime = periodStartTime;
insertWork(periodicWork);
new WorkerWrapper.Builder(mContext, mDatabase, periodicWork.getStringId())
.withListener(mMockListener)
.build()
.run();
WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
assertThat(updatedWorkSpec.periodStartTime, is(expectedNextPeriodStartTime));
}
@Test
@SmallTest
public void testRun_periodicWork_failure_updatesPeriodStartTime() {
long intervalDuration = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
long periodStartTime = System.currentTimeMillis();
long expectedNextPeriodStartTime = periodStartTime + intervalDuration;
PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
FailureWorker.class, intervalDuration, TimeUnit.MILLISECONDS).build();
getWorkSpec(periodicWork).periodStartTime = periodStartTime;
insertWork(periodicWork);
new WorkerWrapper.Builder(mContext, mDatabase, periodicWork.getStringId())
.withListener(mMockListener)
.build()
.run();
WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
assertThat(updatedWorkSpec.periodStartTime, is(expectedNextPeriodStartTime));
}
@Test
@SmallTest
public void testPeriodicWork_success() {
PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
TestWorker.class,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS)
.build();
final String periodicWorkId = periodicWork.getStringId();
insertWork(periodicWork);
new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
.withListener(mMockListener)
.build()
.run();
WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
verify(mMockListener).onExecuted(periodicWorkId, true, false);
assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
}
@Test
@SmallTest
public void testPeriodicWork_fail() {
PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
FailureWorker.class,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS)
.build();
final String periodicWorkId = periodicWork.getStringId();
insertWork(periodicWork);
new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
.withListener(mMockListener)
.build()
.run();
WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
verify(mMockListener).onExecuted(periodicWorkId, false, false);
assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
}
@Test
@SmallTest
public void testPeriodicWork_retry() {
PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
RetryWorker.class,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS)
.build();
final String periodicWorkId = periodicWork.getStringId();
insertWork(periodicWork);
new WorkerWrapper.Builder(mContext, mDatabase, periodicWorkId)
.withListener(mMockListener)
.build()
.run();
WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
verify(mMockListener).onExecuted(periodicWorkId, false, true);
assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(1));
assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
}
@Test
@SmallTest
public void testScheduler() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
Scheduler mockScheduler = mock(Scheduler.class);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mockScheduler))
.build()
.run();
verify(mockScheduler).schedule();
}
@Test
@SmallTest
public void testFromWorkSpec_hasAppContext() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Worker worker = WorkerWrapper.workerFromWorkSpec(
mContext,
getWorkSpec(work),
new Extras(Data.EMPTY, Collections.<String>emptyList(), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.getApplicationContext(), is(equalTo(mContext.getApplicationContext())));
}
@Test
@SmallTest
public void testFromWorkSpec_hasCorrectArguments() {
String key = "KEY";
String expectedValue = "VALUE";
Data input = new Data.Builder().putString(key, expectedValue).build();
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(TestWorker.class).setInputData(input).build();
Worker worker = WorkerWrapper.workerFromWorkSpec(
mContext,
getWorkSpec(work),
new Extras(input, Collections.<String>emptyList(), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.getInputData().getString(key, null), is(expectedValue));
work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
worker = WorkerWrapper.workerFromWorkSpec(
mContext,
getWorkSpec(work),
new Extras(Data.EMPTY, Collections.<String>emptyList(), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.getInputData().size(), is(0));
}
@Test
@SmallTest
public void testFromWorkSpec_hasCorrectTags() {
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(TestWorker.class)
.addTag("one")
.addTag("two")
.addTag("three")
.build();
Worker worker = WorkerWrapper.workerFromWorkSpec(
mContext,
getWorkSpec(work),
new Extras(Data.EMPTY, Arrays.asList("one", "two", "three"), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.getTags(), containsInAnyOrder("one", "two", "three"));
}
@Test
@SmallTest
public void testFromWorkSpec_hasCorrectRuntimeExtras() {
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(TestWorker.class).build();
Extras.RuntimeExtras runtimeExtras = new Extras.RuntimeExtras();
runtimeExtras.triggeredContentAuthorities = new String[] { "tca1", "tca2", "tca3" };
runtimeExtras.triggeredContentUris = new Uri[] { Uri.parse("tcu1"), Uri.parse("tcu2") };
Worker worker = WorkerWrapper.workerFromWorkSpec(
mContext,
getWorkSpec(work),
new Extras(Data.EMPTY, Collections.<String>emptyList(), runtimeExtras, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.getTriggeredContentAuthorities(),
arrayContaining(runtimeExtras.triggeredContentAuthorities));
assertThat(worker.getTriggeredContentUris(),
arrayContaining(runtimeExtras.triggeredContentUris));
}
@Test
@SmallTest
public void testSuccess_withPendingScheduledWork() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
OneTimeWorkRequest unscheduled = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(unscheduled);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
verify(mMockScheduler, times(1)).schedule(unscheduled.getWorkSpec());
verify(mMockListener).onExecuted(work.getStringId(), true, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(SUCCEEDED));
}
@Test
@SmallTest
public void testFailure_withPendingScheduledWork() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
insertWork(work);
OneTimeWorkRequest unscheduled = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(unscheduled);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
verify(mMockScheduler, times(1)).schedule(unscheduled.getWorkSpec());
verify(mMockListener).onExecuted(work.getStringId(), false, false);
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
}
@Test
@LargeTest
public void testInterruption() throws InterruptedException {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build();
Executors.newSingleThreadExecutor().submit(workerWrapper);
workerWrapper.interrupt(false);
Thread.sleep(6000L);
verify(mMockListener).onExecuted(work.getStringId(), false, true);
}
@Test
@SmallTest
public void testInterruptionWithoutCancellation_isMarkedOnRunningWorker() {
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(InterruptionAwareWorker.class).build();
insertWork(work);
Worker worker = WorkerWrapper.workerFromClassName(
mContext,
InterruptionAwareWorker.class.getName(),
work.getId(),
new Extras(Data.EMPTY, Collections.<String>emptyList(), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.isStopped(), is(false));
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.withWorker(worker)
.build();
Executors.newSingleThreadExecutor().submit(workerWrapper);
workerWrapper.interrupt(false);
assertThat(worker.isStopped(), is(true));
assertThat(worker.isCancelled(), is(false));
}
@Test
@SmallTest
public void testInterruptionWithCancellation_isMarkedOnRunningWorker() {
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(InterruptionAwareWorker.class).build();
insertWork(work);
Worker worker = WorkerWrapper.workerFromClassName(
mContext,
InterruptionAwareWorker.class.getName(),
work.getId(),
new Extras(Data.EMPTY, Collections.<String>emptyList(), null, 1));
assertThat(worker, is(notNullValue()));
assertThat(worker.isStopped(), is(false));
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.withWorker(worker)
.build();
Executors.newSingleThreadExecutor().submit(workerWrapper);
workerWrapper.interrupt(true);
assertThat(worker.isStopped(), is(true));
assertThat(worker.isCancelled(), is(true));
}
@Test
@SmallTest
public void testException_isTreatedAsFailure() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(ExceptionWorker.class).build();
insertWork(work);
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build()
.run();
assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
}
@Test
@LargeTest
public void testWorkerWrapper_handlesWorkSpecDeletion() throws InterruptedException {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(SleepTestWorker.class).build();
insertWork(work);
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build();
Executors.newSingleThreadExecutor().submit(workerWrapper);
mWorkSpecDao.delete(work.getStringId());
Thread.sleep(6000L);
verify(mMockListener).onExecuted(work.getStringId(), false, false);
}
@Test
@LargeTest
public void testWorker_getsRunAttemptCount() throws InterruptedException {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(InfiniteTestWorker.class)
.setInitialRunAttemptCount(10)
.build();
insertWork(work);
WorkerWrapper workerWrapper =
new WorkerWrapper.Builder(mContext, mDatabase, work.getStringId())
.withSchedulers(Collections.singletonList(mMockScheduler))
.withListener(mMockListener)
.build();
Executors.newSingleThreadExecutor().submit(workerWrapper);
Thread.sleep(1000L);
assertThat(workerWrapper.mWorker.getRunAttemptCount(), is(10));
}
}