blob: 8510b51bfdc1838c371b64c5ff5aa2d4da7e91ed [file] [log] [blame]
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -07001/*
Sumir Katariada315bf2017-12-06 16:29:10 -08002 * Copyright 2017 The Android Open Source Project
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -07003 *
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
Sumir Kataria564e4302018-02-14 11:22:30 -080017package androidx.work.impl;
Sumir Katariab6430f22018-02-05 13:45:22 -080018
Sergey Vasilinetsafb21272023-06-01 00:00:03 +010019import static android.app.job.JobParameters.STOP_REASON_CONSTRAINT_CHARGING;
20
Rahul Ravikumar7f7ab612018-11-01 16:22:11 -070021import static androidx.work.WorkInfo.State.BLOCKED;
22import static androidx.work.WorkInfo.State.CANCELLED;
23import static androidx.work.WorkInfo.State.ENQUEUED;
24import static androidx.work.WorkInfo.State.FAILED;
25import static androidx.work.WorkInfo.State.RUNNING;
26import static androidx.work.WorkInfo.State.SUCCEEDED;
Sumir Katariab5728f42018-03-19 12:58:41 -070027
Sumir Katariada315bf2017-12-06 16:29:10 -080028import static org.hamcrest.CoreMatchers.equalTo;
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +000029import static org.hamcrest.CoreMatchers.instanceOf;
Jan Clarin9e3c28e2017-09-29 16:18:41 -070030import static org.hamcrest.CoreMatchers.is;
Sumir Katariada315bf2017-12-06 16:29:10 -080031import static org.hamcrest.CoreMatchers.notNullValue;
Kuan-Ying Chou039d414b2024-01-29 11:43:38 +000032import static org.hamcrest.CoreMatchers.nullValue;
Jan Clarin9e3c28e2017-09-29 16:18:41 -070033import static org.hamcrest.MatcherAssert.assertThat;
Sumir Kataria9244d372017-11-30 13:39:07 -080034import static org.hamcrest.Matchers.contains;
Sumir Kataria9e637902017-11-27 14:03:47 -080035import static org.hamcrest.Matchers.containsInAnyOrder;
Jan Clarin0deb5e22017-12-06 11:26:29 -080036import static org.hamcrest.Matchers.greaterThan;
Sergey Vasilinetc68a31442023-09-21 16:31:00 +010037import static org.hamcrest.Matchers.greaterThanOrEqualTo;
Sumir Katariac4fde482018-12-11 12:58:51 -080038import static org.hamcrest.Matchers.isOneOf;
Sumir Kataria9554b662017-10-02 14:49:46 -070039import static org.mockito.Mockito.mock;
Xyan Bhatnagard7b783e2017-09-22 14:21:25 -070040
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -070041import static java.util.concurrent.TimeUnit.HOURS;
42import static java.util.concurrent.TimeUnit.MINUTES;
43
Sergey Vasilinetsafb21272023-06-01 00:00:03 +010044import android.annotation.SuppressLint;
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -070045import android.content.Context;
Sumir Kataria7b5c5602018-05-21 15:51:33 -070046import android.net.Uri;
Sumir Kataria5c0277e2018-09-24 13:24:18 -070047import android.util.Log;
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -070048
Rahul Ravikumar74eb3302019-08-27 14:23:43 -070049import androidx.annotation.NonNull;
50import androidx.annotation.Nullable;
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +000051import androidx.core.util.Consumer;
Alan Viverettebadf2f82018-12-18 12:14:10 -050052import androidx.test.core.app.ApplicationProvider;
53import androidx.test.ext.junit.runners.AndroidJUnit4;
Aurimas Liutikasb7eeda42018-07-10 11:57:16 -070054import androidx.test.filters.LargeTest;
Rahul Ravikumar288b32d2019-08-28 09:37:37 -070055import androidx.test.filters.MediumTest;
Rahul Ravikumar74eb3302019-08-27 14:23:43 -070056import androidx.test.filters.SdkSuppress;
Aurimas Liutikasb7eeda42018-07-10 11:57:16 -070057import androidx.test.filters.SmallTest;
Rahul Ravikumar9bcde552020-05-18 16:25:26 -070058import androidx.testutils.RepeatRule;
Sumir Kataria564e4302018-02-14 11:22:30 -080059import androidx.work.ArrayCreatingInputMerger;
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -070060import androidx.work.BackoffPolicy;
Rahul Ravikumare3265922018-06-07 16:35:15 -070061import androidx.work.Configuration;
Sumir Kataria64e6bd82018-03-28 17:14:22 -070062import androidx.work.Data;
Sumir Kataria564e4302018-02-14 11:22:30 -080063import androidx.work.DatabaseTest;
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -070064import androidx.work.ForegroundUpdater;
Sumir Kataria32f10f672018-09-28 15:00:45 -070065import androidx.work.ListenableWorker;
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -070066import androidx.work.OneTimeWorkRequest;
Sumir Kataria8b3284f2018-04-13 09:50:18 -070067import androidx.work.PeriodicWorkRequest;
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -070068import androidx.work.ProgressUpdater;
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +010069import androidx.work.WorkInfo;
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -070070import androidx.work.WorkRequest;
71import androidx.work.Worker;
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +000072import androidx.work.WorkerExceptionInfo;
73import androidx.work.WorkerFactory;
Sumir Katariaf82a3d62018-09-12 14:18:23 -070074import androidx.work.WorkerParameters;
Rahul Ravikumar15f468c2019-08-30 15:09:02 -070075import androidx.work.impl.foreground.ForegroundProcessor;
Sumir Kataria564e4302018-02-14 11:22:30 -080076import androidx.work.impl.model.Dependency;
77import androidx.work.impl.model.DependencyDao;
78import androidx.work.impl.model.WorkSpec;
79import androidx.work.impl.model.WorkSpecDao;
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -070080import androidx.work.impl.testutils.TestOverrideClock;
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +010081import androidx.work.impl.testutils.TrackingWorkerFactory;
Sumir Kataria2cea33c2018-09-07 15:10:39 -070082import androidx.work.impl.utils.SynchronousExecutor;
Sumir Kataria8df18fe2018-08-23 10:19:02 -070083import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor;
84import androidx.work.impl.utils.taskexecutor.TaskExecutor;
Sumir Kataria564e4302018-02-14 11:22:30 -080085import androidx.work.worker.ChainedArgumentWorker;
86import androidx.work.worker.EchoingWorker;
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +000087import androidx.work.worker.ExceptionInConstructionWorker;
Sumir Kataria3f0c0fb2018-05-07 16:24:48 -070088import androidx.work.worker.ExceptionWorker;
Sumir Kataria564e4302018-02-14 11:22:30 -080089import androidx.work.worker.FailureWorker;
Sumir Katariabf4f4f72018-05-22 11:23:27 -070090import androidx.work.worker.InterruptionAwareWorker;
Sumir Kataria5c0277e2018-09-24 13:24:18 -070091import androidx.work.worker.LatchWorker;
Kuan-Ying Chou039d414b2024-01-29 11:43:38 +000092import androidx.work.worker.NeverResolvedWorker;
Sumir Kataria564e4302018-02-14 11:22:30 -080093import androidx.work.worker.RetryWorker;
Rahul Ravikumard64fb002018-12-03 13:10:53 -080094import androidx.work.worker.ReturnNullResultWorker;
Sumir Kataria564e4302018-02-14 11:22:30 -080095import androidx.work.worker.TestWorker;
Sumir Kataria768d1602018-09-17 14:09:06 -070096import androidx.work.worker.UsedWorker;
Sumir Kataria564e4302018-02-14 11:22:30 -080097
Sergey Vasilinetsd0ac2cc2018-09-12 11:23:16 -070098import com.google.common.util.concurrent.ListenableFuture;
99
Rahul Ravikumarf13c2352019-12-16 10:45:17 -0800100import org.junit.After;
Sumir Katariab5728f42018-03-19 12:58:41 -0700101import org.junit.Before;
Rahul Ravikumar9bcde552020-05-18 16:25:26 -0700102import org.junit.Rule;
Sumir Katariab5728f42018-03-19 12:58:41 -0700103import org.junit.Test;
104import org.junit.runner.RunWith;
Sumir Katariab5728f42018-03-19 12:58:41 -0700105
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +0000106import java.lang.reflect.InvocationTargetException;
Sumir Katariab5728f42018-03-19 12:58:41 -0700107import java.util.Arrays;
108import java.util.Collections;
109import java.util.List;
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100110import java.util.UUID;
Sumir Kataria0c320a82018-09-06 16:20:53 -0700111import java.util.concurrent.ExecutionException;
112import java.util.concurrent.Executor;
Sergey Vasilinets4b07ddb2021-12-16 22:50:01 +0000113import java.util.concurrent.ExecutorService;
Sumir Katariab5728f42018-03-19 12:58:41 -0700114import java.util.concurrent.Executors;
115import java.util.concurrent.TimeUnit;
116
Sergey Vasilinetce46854a2024-02-07 16:45:34 +0000117import kotlinx.coroutines.Dispatchers;
118
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700119@RunWith(AndroidJUnit4.class)
Sumir Kataria9e637902017-11-27 14:03:47 -0800120public class WorkerWrapperTest extends DatabaseTest {
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700121
Rahul Ravikumare3265922018-06-07 16:35:15 -0700122 private Configuration mConfiguration;
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700123 private TaskExecutor mWorkTaskExecutor;
Xyan Bhatnagard7b783e2017-09-22 14:21:25 -0700124 private WorkSpecDao mWorkSpecDao;
Xyan Bhatnagar6463beb2017-09-27 16:37:04 -0700125 private DependencyDao mDependencyDao;
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700126 private Context mContext;
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700127 private TestOverrideClock mTestClock = new TestOverrideClock();
Rahul Ravikumar15f468c2019-08-30 15:09:02 -0700128 private ForegroundProcessor mMockForegroundProcessor;
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -0700129 private ProgressUpdater mMockProgressUpdater;
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -0700130 private ForegroundUpdater mMockForegroundUpdater;
Sumir Kataria2cea33c2018-09-07 15:10:39 -0700131 private Executor mSynchronousExecutor = new SynchronousExecutor();
Sergey Vasilinets4b07ddb2021-12-16 22:50:01 +0000132 private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +0000133 private TestWorkerExceptionHandler mWorkerExceptionHandler;
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700134
135 @Before
Xyan Bhatnagar63ccec52017-09-22 16:09:31 -0700136 public void setUp() {
Alan Viverettebadf2f82018-12-18 12:14:10 -0500137 mContext = ApplicationProvider.getApplicationContext();
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +0000138 mWorkerExceptionHandler = new TestWorkerExceptionHandler();
Sumir Kataria2cea33c2018-09-07 15:10:39 -0700139 mConfiguration = new Configuration.Builder()
140 .setExecutor(new SynchronousExecutor())
Sumir Kataria5c0277e2018-09-24 13:24:18 -0700141 .setMinimumLoggingLevel(Log.VERBOSE)
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700142 .setClock(mTestClock)
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +0000143 .setWorkerInitializationExceptionHandler(mWorkerExceptionHandler)
144 .setWorkerExecutionExceptionHandler(mWorkerExceptionHandler)
Sumir Kataria2cea33c2018-09-07 15:10:39 -0700145 .build();
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700146 mWorkTaskExecutor = new InstantWorkTaskExecutor();
Rahul Ravikumare5356662019-03-04 16:22:14 -0800147 mWorkSpecDao = mDatabase.workSpecDao();
Xyan Bhatnagar6463beb2017-09-27 16:37:04 -0700148 mDependencyDao = mDatabase.dependencyDao();
Rahul Ravikumar15f468c2019-08-30 15:09:02 -0700149 mMockForegroundProcessor = mock(ForegroundProcessor.class);
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -0700150 mMockProgressUpdater = mock(ProgressUpdater.class);
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -0700151 mMockForegroundUpdater = mock(ForegroundUpdater.class);
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700152 }
153
Rahul Ravikumarf13c2352019-12-16 10:45:17 -0800154 @After
155 public void tearDown() {
Sergey Vasilinets4b07ddb2021-12-16 22:50:01 +0000156 mExecutorService.shutdown();
157 try {
158 assertThat(mExecutorService.awaitTermination(3, TimeUnit.SECONDS), is(true));
159 } catch (InterruptedException e) {
160 throw new RuntimeException(e);
161 }
Rahul Ravikumarf13c2352019-12-16 10:45:17 -0800162 mDatabase.close();
163 }
164
Rahul Ravikumar9bcde552020-05-18 16:25:26 -0700165 @Rule
166 public RepeatRule mRepeatRule = new RepeatRule();
167
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700168 @Test
Xyan Bhatnagar687da332017-11-15 10:39:57 -0800169 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700170 public void testSuccess() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700171 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800172 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700173 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
174 FutureListener listener = createAndAddFutureListener(workerWrapper);
175 workerWrapper.run();
176 assertThat(listener.mResult, is(false));
Sumir Katariafa284c92018-04-23 14:25:53 -0700177 assertThat(mWorkSpecDao.getState(work.getStringId()), is(SUCCEEDED));
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700178 }
179
180 @Test
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700181 @SmallTest
182 public void testRunAttemptCountIncremented_successfulExecution() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700183 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800184 insertWork(work);
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700185 createBuilder(work.getStringId())
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700186 .build()
187 .run();
Sumir Katariafa284c92018-04-23 14:25:53 -0700188 WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
Sumir Katariab5728f42018-03-19 12:58:41 -0700189 assertThat(latestWorkSpec.runAttemptCount, is(1));
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700190 }
191
192 @Test
193 @SmallTest
194 public void testRunAttemptCountIncremented_failedExecution() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700195 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800196 insertWork(work);
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700197 createBuilder(work.getStringId())
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700198 .build()
199 .run();
Sumir Katariafa284c92018-04-23 14:25:53 -0700200 WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
Sumir Katariaa3262882018-08-17 16:15:35 -0700201 assertThat(latestWorkSpec.runAttemptCount, is(1));
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700202 }
203
204 @Test
Jan Clarinee302e12017-10-09 11:16:19 -0700205 @SmallTest
Sumir Kataria4184cf02018-07-10 13:24:17 -0700206 public void testInvalidWorkerClassName() {
207 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
208 work.getWorkSpec().workerClassName = "dummy";
209 insertWork(work);
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100210 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
Sumir Kataria0c320a82018-09-06 16:20:53 -0700211 FutureListener listener = createAndAddFutureListener(workerWrapper);
212 workerWrapper.run();
213 assertThat(listener.mResult, is(false));
Sumir Kataria4184cf02018-07-10 13:24:17 -0700214 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
215 }
216
Rahul Ravikumar2114e282019-08-16 15:26:16 -0700217 @Test(expected = IllegalStateException.class)
Sumir Kataria4184cf02018-07-10 13:24:17 -0700218 @SmallTest
Sumir Kataria768d1602018-09-17 14:09:06 -0700219 public void testUsedWorker_failsExecution() {
220 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
221 insertWork(work);
Sumir Katariaa5658ce2018-09-27 15:02:32 -0700222
Sumir Kataria931889d2018-10-01 12:44:42 -0700223 UsedWorker usedWorker = (UsedWorker) mConfiguration.getWorkerFactory()
224 .createWorkerWithDefaultFallback(
225 mContext.getApplicationContext(),
226 UsedWorker.class.getName(),
227 new WorkerParameters(
228 work.getId(),
229 Data.EMPTY,
230 work.getTags(),
231 new WorkerParameters.RuntimeExtras(),
232 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +0100233 0,
Sumir Kataria931889d2018-10-01 12:44:42 -0700234 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +0000235 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -0700236 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -0700237 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -0700238 mMockProgressUpdater,
239 mMockForegroundUpdater));
Sumir Katariaa5658ce2018-09-27 15:02:32 -0700240
Sumir Kataria768d1602018-09-17 14:09:06 -0700241 WorkerWrapper workerWrapper = createBuilder(work.getStringId())
Sumir Katariaa5658ce2018-09-27 15:02:32 -0700242 .withWorker(usedWorker)
Sumir Kataria768d1602018-09-17 14:09:06 -0700243 .build();
244 workerWrapper.run();
Sumir Kataria768d1602018-09-17 14:09:06 -0700245 }
246
247 @Test
248 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700249 public void testNotEnqueued() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700250 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700251 .setInitialState(RUNNING)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700252 .build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800253 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700254 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
255 FutureListener listener = createAndAddFutureListener(workerWrapper);
256 workerWrapper.run();
257 assertThat(listener.mResult, is(true));
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -0700258 }
259
260 @Test
Xyan Bhatnagar687da332017-11-15 10:39:57 -0800261 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700262 public void testCancelled() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700263 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria5b84f5c2018-05-04 14:34:49 +0000264 .setInitialState(CANCELLED)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700265 .build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800266 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700267 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
268 FutureListener listener = createAndAddFutureListener(workerWrapper);
269 workerWrapper.run();
270 assertThat(listener.mResult, is(false));
Sumir Kataria5b84f5c2018-05-04 14:34:49 +0000271 assertThat(mWorkSpecDao.getState(work.getStringId()), is(CANCELLED));
Sumir Kataria2ace67d2017-11-21 13:23:53 -0800272 }
273
274 @Test
275 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700276 public void testPermanentErrorWithInvalidWorkerClass() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700277 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sergey Vasilinetsad24b522021-11-11 17:54:05 +0000278 work.getWorkSpec().workerClassName = "INVALID_CLASS_NAME";
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800279 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700280 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
281 FutureListener listener = createAndAddFutureListener(workerWrapper);
282 workerWrapper.run();
283 assertThat(listener.mResult, is(false));
Sumir Katariafa284c92018-04-23 14:25:53 -0700284 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
Xyan Bhatnagard7b783e2017-09-22 14:21:25 -0700285 }
286
287 @Test
Xyan Bhatnagar687da332017-11-15 10:39:57 -0800288 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700289 public void testPermanentErrorWithInvalidInputMergerClass() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700290 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sergey Vasilinetsad24b522021-11-11 17:54:05 +0000291 work.getWorkSpec().inputMergerClassName = "INVALID_CLASS_NAME";
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800292 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700293 WorkerWrapper workerWrapper = createBuilder(work.getStringId())
Sumir Kataria0c320a82018-09-06 16:20:53 -0700294 .build();
295 FutureListener listener = createAndAddFutureListener(workerWrapper);
296 workerWrapper.run();
297 assertThat(listener.mResult, is(false));
Sumir Katariafa284c92018-04-23 14:25:53 -0700298 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
Xyan Bhatnagar35574572017-12-11 11:26:16 -0800299 }
300
301 @Test
302 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700303 public void testFailed() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700304 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800305 insertWork(work);
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100306 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
Sumir Kataria0c320a82018-09-06 16:20:53 -0700307 FutureListener listener = createAndAddFutureListener(workerWrapper);
308 workerWrapper.run();
309 assertThat(listener.mResult, is(false));
Sumir Katariafa284c92018-04-23 14:25:53 -0700310 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
Xyan Bhatnagar63ccec52017-09-22 16:09:31 -0700311 }
312
313 @Test
Sumir Katariab93bf042019-03-27 13:13:49 -0700314 @LargeTest
Sumir Kataria286a63d2019-03-25 16:37:22 -0700315 public void testFailedOnDeepHierarchy() {
316 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
317 insertWork(work);
318 String previousId = work.getStringId();
319 String firstWorkId = previousId;
320 for (int i = 0; i < 500; ++i) {
321 work = new OneTimeWorkRequest.Builder(FailureWorker.class).build();
322 insertWork(work);
323 mDependencyDao.insertDependency(new Dependency(work.getStringId(), previousId));
324 previousId = work.getStringId();
325 }
326 WorkerWrapper workerWrapper = createBuilder(firstWorkId).build();
Sergey Vasilinetcaf483912024-01-26 22:39:57 +0000327 workerWrapper.setFailedAndResolve(new ListenableWorker.Result.Failure());
Sumir Kataria286a63d2019-03-25 16:37:22 -0700328 assertThat(mWorkSpecDao.getState(firstWorkId), is(FAILED));
329 assertThat(mWorkSpecDao.getState(previousId), is(FAILED));
330 }
331
332 @Test
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700333 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700334 public void testRunning_onlyWhenEnqueued() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700335 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700336 .setInitialState(RUNNING)
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700337 .build();
338 insertWork(work);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700339 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
340 FutureListener listener = createAndAddFutureListener(workerWrapper);
341 workerWrapper.run();
342 assertThat(listener.mResult, is(true));
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700343 }
344
345 @Test
346 @SmallTest
Sumir Kataria9244d372017-11-30 13:39:07 -0800347 public void testDependencies_passesOutputs() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700348 OneTimeWorkRequest prerequisiteWork =
349 new OneTimeWorkRequest.Builder(ChainedArgumentWorker.class).build();
350 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700351 .setInitialState(BLOCKED)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700352 .build();
Sumir Katariafa284c92018-04-23 14:25:53 -0700353 Dependency dependency = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
Sumir Kataria1e9589d2017-11-22 13:23:46 -0800354
355 mDatabase.beginTransaction();
356 try {
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800357 insertWork(prerequisiteWork);
358 insertWork(work);
Sumir Kataria1e9589d2017-11-22 13:23:46 -0800359 mDependencyDao.insertDependency(dependency);
360 mDatabase.setTransactionSuccessful();
361 } finally {
362 mDatabase.endTransaction();
363 }
364
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700365 createBuilder(prerequisiteWork.getStringId())
Rahul Ravikumar9f91ee82018-03-20 17:33:38 -0700366 .build().run();
Sumir Kataria1e9589d2017-11-22 13:23:46 -0800367
Sumir Katariafa284c92018-04-23 14:25:53 -0700368 List<Data> arguments = mWorkSpecDao.getInputsFromPrerequisites(work.getStringId());
Sumir Kataria9244d372017-11-30 13:39:07 -0800369 assertThat(arguments.size(), is(1));
370 assertThat(arguments, contains(ChainedArgumentWorker.getChainedArguments()));
Sumir Kataria1e9589d2017-11-22 13:23:46 -0800371 }
372
373 @Test
374 @SmallTest
Sumir Kataria9244d372017-11-30 13:39:07 -0800375 public void testDependencies_passesMergedOutputs() {
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800376 String key = "key";
377 String value1 = "value1";
378 String value2 = "value2";
379
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700380 OneTimeWorkRequest prerequisiteWork1 = new OneTimeWorkRequest.Builder(EchoingWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700381 .setInputData(new Data.Builder().putString(key, value1).build())
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800382 .build();
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700383 OneTimeWorkRequest prerequisiteWork2 = new OneTimeWorkRequest.Builder(EchoingWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700384 .setInputData(new Data.Builder().putString(key, value2).build())
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800385 .build();
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700386 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700387 .setInputMerger(ArrayCreatingInputMerger.class)
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800388 .build();
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100389 String id = work.getStringId();
Sumir Katariafa284c92018-04-23 14:25:53 -0700390 Dependency dependency1 =
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100391 new Dependency(id, prerequisiteWork1.getStringId());
Sumir Katariafa284c92018-04-23 14:25:53 -0700392 Dependency dependency2 =
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100393 new Dependency(id, prerequisiteWork2.getStringId());
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800394
395 mDatabase.beginTransaction();
396 try {
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800397 insertWork(prerequisiteWork1);
398 insertWork(prerequisiteWork2);
399 insertWork(work);
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800400 mDependencyDao.insertDependency(dependency1);
401 mDependencyDao.insertDependency(dependency2);
402 mDatabase.setTransactionSuccessful();
403 } finally {
404 mDatabase.endTransaction();
405 }
406
407 // Run the prerequisites.
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100408 createBuilder(prerequisiteWork1.getStringId()).build().run();
Rahul Ravikumar9f91ee82018-03-20 17:33:38 -0700409
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100410 createBuilder(prerequisiteWork2.getStringId()).build().run();
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800411
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100412 TrackingWorkerFactory factory = new TrackingWorkerFactory();
413 Configuration configuration = new Configuration.Builder(mConfiguration)
414 .setWorkerFactory(factory)
415 .build();
416 WorkerWrapper workerWrapper = new WorkerWrapper.Builder(
417 mContext,
418 configuration,
419 mWorkTaskExecutor,
420 mMockForegroundProcessor,
421 mDatabase,
422 mWorkSpecDao.getWorkSpec(id),
423 mDatabase.workTagDao().getTagsForWorkSpecId(id)
424 ).build();
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800425 // Create and run the dependent work.
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800426 workerWrapper.run();
427
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100428 ListenableWorker worker = factory.awaitWorker(UUID.fromString(id));
429 Data input = worker.getInputData();
Sumir Kataria64e6bd82018-03-28 17:14:22 -0700430 assertThat(input.size(), is(1));
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +0100431 assertThat(Arrays.asList(input.getStringArray(key)), containsInAnyOrder(value1, value2));
Sumir Kataria6ae802c2017-11-29 16:00:44 -0800432 }
433
434 @Test
435 @SmallTest
Jan Clarin0deb5e22017-12-06 11:26:29 -0800436 public void testDependencies_setsPeriodStartTimesForUnblockedWork() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700437 OneTimeWorkRequest prerequisiteWork =
438 new OneTimeWorkRequest.Builder(TestWorker.class).build();
439 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700440 .setInitialState(BLOCKED)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700441 .build();
Sumir Katariafa284c92018-04-23 14:25:53 -0700442 Dependency dependency = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
Jan Clarin0deb5e22017-12-06 11:26:29 -0800443
444 mDatabase.beginTransaction();
445 try {
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800446 insertWork(prerequisiteWork);
447 insertWork(work);
Jan Clarin0deb5e22017-12-06 11:26:29 -0800448 mDependencyDao.insertDependency(dependency);
449 mDatabase.setTransactionSuccessful();
450 } finally {
451 mDatabase.endTransaction();
452 }
453
Sergey Vasilinetc68a31442023-09-21 16:31:00 +0100454 assertThat(mWorkSpecDao.getWorkSpec(work.getStringId()).lastEnqueueTime, is(-1L));
455
Jan Clarin0deb5e22017-12-06 11:26:29 -0800456 long beforeUnblockedTime = System.currentTimeMillis();
457
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100458 createBuilder(prerequisiteWork.getStringId()).build().run();
Jan Clarin0deb5e22017-12-06 11:26:29 -0800459
Sumir Katariafa284c92018-04-23 14:25:53 -0700460 WorkSpec workSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
Sergey Vasilinetc68a31442023-09-21 16:31:00 +0100461 assertThat(workSpec.lastEnqueueTime, is(greaterThanOrEqualTo(beforeUnblockedTime)));
Jan Clarin0deb5e22017-12-06 11:26:29 -0800462 }
463
464 @Test
465 @SmallTest
Sumir Katariac4fde482018-12-11 12:58:51 -0800466 public void testDependencies_enqueuesBlockedDependentsOnSuccess() {
467 OneTimeWorkRequest prerequisiteWork =
468 new OneTimeWorkRequest.Builder(TestWorker.class).build();
469 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
470 .setInitialState(BLOCKED)
471 .build();
472 OneTimeWorkRequest cancelledWork = new OneTimeWorkRequest.Builder(TestWorker.class)
473 .setInitialState(CANCELLED)
474 .build();
475 Dependency dependency1 = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
476 Dependency dependency2 =
477 new Dependency(cancelledWork.getStringId(), prerequisiteWork.getStringId());
478
479 mDatabase.beginTransaction();
480 try {
481 insertWork(prerequisiteWork);
482 insertWork(work);
483 insertWork(cancelledWork);
484 mDependencyDao.insertDependency(dependency1);
485 mDependencyDao.insertDependency(dependency2);
486 mDatabase.setTransactionSuccessful();
487 } finally {
488 mDatabase.endTransaction();
489 }
490
491 createBuilder(prerequisiteWork.getStringId())
492 .build()
493 .run();
494
495 assertThat(mWorkSpecDao.getState(prerequisiteWork.getStringId()), is(SUCCEEDED));
496 assertThat(mWorkSpecDao.getState(work.getStringId()),
497 isOneOf(ENQUEUED, RUNNING, SUCCEEDED));
498 assertThat(mWorkSpecDao.getState(cancelledWork.getStringId()), is(CANCELLED));
499 }
500
501 @Test
502 @SmallTest
Sumir Katariac1ba6332018-03-06 16:54:45 -0800503 public void testDependencies_failsUncancelledDependentsOnFailure() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700504 OneTimeWorkRequest prerequisiteWork =
505 new OneTimeWorkRequest.Builder(FailureWorker.class).build();
506 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria62a7e772018-04-23 21:12:57 -0700507 .setInitialState(BLOCKED)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700508 .build();
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -0700509 OneTimeWorkRequest cancelledWork = new OneTimeWorkRequest.Builder(TestWorker.class)
Sumir Kataria5b84f5c2018-05-04 14:34:49 +0000510 .setInitialState(CANCELLED)
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700511 .build();
Sumir Katariafa284c92018-04-23 14:25:53 -0700512 Dependency dependency1 = new Dependency(work.getStringId(), prerequisiteWork.getStringId());
513 Dependency dependency2 =
514 new Dependency(cancelledWork.getStringId(), prerequisiteWork.getStringId());
Sumir Katariac1ba6332018-03-06 16:54:45 -0800515
516 mDatabase.beginTransaction();
517 try {
518 insertWork(prerequisiteWork);
519 insertWork(work);
520 insertWork(cancelledWork);
521 mDependencyDao.insertDependency(dependency1);
522 mDependencyDao.insertDependency(dependency2);
523 mDatabase.setTransactionSuccessful();
524 } finally {
525 mDatabase.endTransaction();
526 }
527
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700528 createBuilder(prerequisiteWork.getStringId())
Sumir Katariafa284c92018-04-23 14:25:53 -0700529 .build()
530 .run();
Sumir Katariac1ba6332018-03-06 16:54:45 -0800531
Sumir Katariafa284c92018-04-23 14:25:53 -0700532 assertThat(mWorkSpecDao.getState(prerequisiteWork.getStringId()), is(FAILED));
533 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
Sumir Kataria5b84f5c2018-05-04 14:34:49 +0000534 assertThat(mWorkSpecDao.getState(cancelledWork.getStringId()), is(CANCELLED));
Sumir Katariac1ba6332018-03-06 16:54:45 -0800535 }
536
537 @Test
538 @SmallTest
Rahul Ravikumar1cb6e002019-01-15 14:24:59 -0800539 public void testBackedOffOneTimeWork_doesNotRun() {
540 OneTimeWorkRequest retryWork =
541 new OneTimeWorkRequest.Builder(RetryWorker.class).build();
542
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700543 long future = System.currentTimeMillis() + HOURS.toMillis(1);
Rahul Ravikumar1cb6e002019-01-15 14:24:59 -0800544 mDatabase.beginTransaction();
545 try {
546 mWorkSpecDao.insertWorkSpec(retryWork.getWorkSpec());
Faelyn O'Grady1385abc2023-03-03 15:12:08 -0800547 mWorkSpecDao.setLastEnqueueTime(retryWork.getStringId(), future);
Rahul Ravikumar1cb6e002019-01-15 14:24:59 -0800548 mWorkSpecDao.incrementWorkSpecRunAttemptCount(retryWork.getStringId());
549 mDatabase.setTransactionSuccessful();
550 } finally {
551 mDatabase.endTransaction();
552 }
553
554 createBuilder(retryWork.getStringId())
555 .build()
556 .run();
557
558 WorkSpec workSpec = mWorkSpecDao.getWorkSpec(retryWork.getStringId());
559 // The run attempt count should remain the same
560 assertThat(workSpec.runAttemptCount, is(1));
561 }
562
563 @Test
564 @SmallTest
Jan Clarin0deb5e22017-12-06 11:26:29 -0800565 public void testRun_periodicWork_success_updatesPeriodStartTime() {
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700566 long intervalDurationMillis = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
567 long periodStartTimeMillis = System.currentTimeMillis();
Jan Clarin0deb5e22017-12-06 11:26:29 -0800568
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700569 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700570 TestWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS).build();
Jan Clarin0deb5e22017-12-06 11:26:29 -0800571
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700572 periodicWork.getWorkSpec().lastEnqueueTime = periodStartTimeMillis;
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800573 insertWork(periodicWork);
Jan Clarin0deb5e22017-12-06 11:26:29 -0800574
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700575 createBuilder(periodicWork.getStringId())
Jan Clarin0deb5e22017-12-06 11:26:29 -0800576 .build()
577 .run();
578
Sumir Katariafa284c92018-04-23 14:25:53 -0700579 WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700580 assertThat(updatedWorkSpec.calculateNextRunTime(), greaterThan(periodStartTimeMillis));
Jan Clarin0deb5e22017-12-06 11:26:29 -0800581 }
582
583 @Test
584 @SmallTest
585 public void testRun_periodicWork_failure_updatesPeriodStartTime() {
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700586 long intervalDurationMillis = PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
587 long periodStartTimeMillis = System.currentTimeMillis();
Jan Clarin0deb5e22017-12-06 11:26:29 -0800588
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700589 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700590 FailureWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS).build();
Jan Clarin0deb5e22017-12-06 11:26:29 -0800591
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700592 periodicWork.getWorkSpec().lastEnqueueTime = periodStartTimeMillis;
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800593 insertWork(periodicWork);
Jan Clarin0deb5e22017-12-06 11:26:29 -0800594
Sumir Kataria8df18fe2018-08-23 10:19:02 -0700595 createBuilder(periodicWork.getStringId())
Jan Clarin0deb5e22017-12-06 11:26:29 -0800596 .build()
597 .run();
598
Sumir Katariafa284c92018-04-23 14:25:53 -0700599 WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700600 assertThat(updatedWorkSpec.calculateNextRunTime(), greaterThan(periodStartTimeMillis));
Jan Clarin0deb5e22017-12-06 11:26:29 -0800601 }
602
603 @Test
604 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700605 public void testPeriodicWork_success() {
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700606 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
Sumir Kataria3f630c92017-10-24 16:38:54 -0700607 TestWorker.class,
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700608 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
Sumir Katariaf4ae2b72018-03-06 10:54:57 -0800609 TimeUnit.MILLISECONDS)
Jan Clarinee302e12017-10-09 11:16:19 -0700610 .build();
611
Sumir Katariafa284c92018-04-23 14:25:53 -0700612 final String periodicWorkId = periodicWork.getStringId();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800613 insertWork(periodicWork);
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100614 WorkerWrapper workerWrapper = createBuilder(periodicWorkId).build();
Sumir Kataria0c320a82018-09-06 16:20:53 -0700615 FutureListener listener = createAndAddFutureListener(workerWrapper);
616 workerWrapper.run();
Jan Clarinee302e12017-10-09 11:16:19 -0700617
Jan Clarinee302e12017-10-09 11:16:19 -0700618 WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700619 assertThat(listener.mResult, is(false));
Sumir Katariab5728f42018-03-19 12:58:41 -0700620 assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
621 assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
Jan Clarinee302e12017-10-09 11:16:19 -0700622 }
623
624 @Test
Xyan Bhatnagar367c6492017-10-06 11:20:02 -0700625 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700626 public void testPeriodicWork_fail() {
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700627 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800628 FailureWorker.class,
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700629 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
Sumir Katariaf4ae2b72018-03-06 10:54:57 -0800630 TimeUnit.MILLISECONDS)
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800631 .build();
632
Sumir Katariafa284c92018-04-23 14:25:53 -0700633 final String periodicWorkId = periodicWork.getStringId();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800634 insertWork(periodicWork);
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100635 WorkerWrapper workerWrapper = createBuilder(periodicWorkId).build();
Sumir Kataria0c320a82018-09-06 16:20:53 -0700636 FutureListener listener = createAndAddFutureListener(workerWrapper);
637 workerWrapper.run();
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800638
639 WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700640 assertThat(listener.mResult, is(false));
Sumir Katariab5728f42018-03-19 12:58:41 -0700641 assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
642 assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800643 }
644
645 @Test
646 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -0700647 public void testPeriodicWork_retry() {
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700648 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800649 RetryWorker.class,
Sumir Kataria8b3284f2018-04-13 09:50:18 -0700650 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
Sumir Katariaf4ae2b72018-03-06 10:54:57 -0800651 TimeUnit.MILLISECONDS)
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800652 .build();
653
Sumir Katariafa284c92018-04-23 14:25:53 -0700654 final String periodicWorkId = periodicWork.getStringId();
Sumir Kataria1cd0e4e2017-12-12 10:53:46 -0800655 insertWork(periodicWork);
Sergey Vasilinets9c84d342022-09-22 11:44:05 +0100656 WorkerWrapper workerWrapper = createBuilder(periodicWorkId).build();
Sumir Kataria0c320a82018-09-06 16:20:53 -0700657 FutureListener listener = createAndAddFutureListener(workerWrapper);
658 workerWrapper.run();
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800659
660 WorkSpec periodicWorkSpecAfterFirstRun = mWorkSpecDao.getWorkSpec(periodicWorkId);
Sumir Kataria0c320a82018-09-06 16:20:53 -0700661 assertThat(listener.mResult, is(true));
Sumir Katariab5728f42018-03-19 12:58:41 -0700662 assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(1));
663 assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800664 }
665
Rahul Ravikumar82d2db92019-01-04 11:28:27 -0800666
667 @Test
668 @SmallTest
669 public void testPeriodic_dedupe() {
670 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
671 TestWorker.class,
672 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
673 TimeUnit.MILLISECONDS)
674 .build();
675
676 final String periodicWorkId = periodicWork.getStringId();
677 final WorkSpec workSpec = periodicWork.getWorkSpec();
678 long now = System.currentTimeMillis();
Sergey Vasilinets681ca8c2022-01-26 16:53:05 +0000679 workSpec.lastEnqueueTime = now + workSpec.intervalDuration;
680 workSpec.setPeriodCount(1);
Rahul Ravikumar82d2db92019-01-04 11:28:27 -0800681 insertWork(periodicWork);
682 WorkerWrapper workerWrapper = createBuilder(periodicWorkId).build();
683 FutureListener listener = createAndAddFutureListener(workerWrapper);
684 workerWrapper.run();
Rahul Ravikumarebb4f872019-01-29 16:16:17 -0800685 // Should get rescheduled
686 assertThat(listener.mResult, is(true));
Rahul Ravikumar82d2db92019-01-04 11:28:27 -0800687 }
688
Xyan Bhatnagarfdd887f2017-11-17 16:44:55 -0800689 @Test
690 @SmallTest
Sergey Vasilinets681ca8c2022-01-26 16:53:05 +0000691 public void testPeriodic_firstRun_flexApplied() {
Rahul Ravikumar6dc75802019-02-12 15:41:35 -0800692 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
693 TestWorker.class,
694 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
695 TimeUnit.MILLISECONDS,
696 PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
697 TimeUnit.MILLISECONDS)
698 .build();
699
700 final String periodicWorkId = periodicWork.getStringId();
701 final WorkSpec workSpec = periodicWork.getWorkSpec();
Sergey Vasilinets681ca8c2022-01-26 16:53:05 +0000702 workSpec.lastEnqueueTime = System.currentTimeMillis();
Rahul Ravikumar6dc75802019-02-12 15:41:35 -0800703 insertWork(periodicWork);
704 WorkerWrapper workerWrapper = createBuilder(periodicWorkId).build();
705 FutureListener listener = createAndAddFutureListener(workerWrapper);
706 workerWrapper.run();
Sergey Vasilinets681ca8c2022-01-26 16:53:05 +0000707 // Should get rescheduled because flex should be respected.
708 assertThat(listener.mResult, is(true));
Rahul Ravikumar6dc75802019-02-12 15:41:35 -0800709 }
710
711 @Test
712 @SmallTest
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -0700713 public void testNextScheduleTimeOverride_delayNormalNextSchedule() {
714 mTestClock.currentTimeMillis = HOURS.toMillis(5);
715 long lastEnqueueTimeMillis = HOURS.toMillis(4);
716 long intervalDurationMillis = HOURS.toMillis(1);
717 // Delay the next run
718 long nextScheduleTimeOverrideMillis = lastEnqueueTimeMillis + HOURS.toMillis(10);
719
720 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
721 TestWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
722 .setNextScheduleTimeOverride(nextScheduleTimeOverrideMillis)
723 .build();
724
725 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
726 insertWork(periodicWork);
727
728 // Try to run when the normal period would have happened
729 mTestClock.currentTimeMillis = lastEnqueueTimeMillis + intervalDurationMillis + 1;
730 createBuilder(periodicWork.getStringId()).build().run();
731
732 // Didn't actually run or do anything, since it's too soon to run
733 WorkSpec firstTryWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
734 assertThat(firstTryWorkSpec.getNextScheduleTimeOverride(),
735 equalTo(nextScheduleTimeOverrideMillis));
736 assertThat(firstTryWorkSpec.getPeriodCount(), equalTo(0));
737 assertThat(firstTryWorkSpec.calculateNextRunTime(),
738 equalTo(nextScheduleTimeOverrideMillis));
739
740 // Try again at the override time
741 long actualWorkRunTime = nextScheduleTimeOverrideMillis;
742 mTestClock.currentTimeMillis = actualWorkRunTime;
743 createBuilder(periodicWork.getStringId()).build().run();
744
745 // Override is cleared and we're scheduled for now + period
746 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
747 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(Long.MAX_VALUE));
748 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(1));
749 assertThat(afterRunWorkSpec.calculateNextRunTime(),
750 equalTo(actualWorkRunTime + intervalDurationMillis));
751 }
752
753 @Test
754 @SmallTest
755 public void testNextScheduleTimeOverride_backsOffNextTimeAfterRetry() {
756 mTestClock.currentTimeMillis = HOURS.toMillis(5);
757 long lastEnqueueTimeMillis = HOURS.toMillis(4);
758 long intervalDurationMillis = HOURS.toMillis(100);
759 long nextScheduleTimeOverrideMillis = lastEnqueueTimeMillis + HOURS.toMillis(10);
760 long backoffLinearDurationMillis = MINUTES.toMillis(30);
761
762 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
763 // RetryWorker always returns Result.Retry
764 RetryWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
765 .setBackoffCriteria(BackoffPolicy.LINEAR, backoffLinearDurationMillis,
766 TimeUnit.MILLISECONDS)
767 .setNextScheduleTimeOverride(nextScheduleTimeOverrideMillis)
768 .build();
769
770 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
771 mTestClock.currentTimeMillis = nextScheduleTimeOverrideMillis;
772 insertWork(periodicWork);
773
774 createBuilder(periodicWork.getStringId()).build().run();
775
776 // Override is cleared and we're rescheduled according to the backoff policy
777 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
778 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(0));
779 assertThat(afterRunWorkSpec.runAttemptCount, equalTo(1));
780 assertThat(afterRunWorkSpec.state, is(ENQUEUED));
781 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(Long.MAX_VALUE));
782 // Should be scheduled again for now + one backoff.
783 assertThat(afterRunWorkSpec.calculateNextRunTime(),
784 equalTo(nextScheduleTimeOverrideMillis + backoffLinearDurationMillis));
785 }
786
787 @Test
788 @SmallTest
789 public void testNextScheduleTimeOverride_whileWorkerIsRunning_appliesToNextRun()
790 throws ExecutionException, InterruptedException {
791 mTestClock.currentTimeMillis = HOURS.toMillis(5);
792 long lastEnqueueTimeMillis = HOURS.toMillis(4);
793 long intervalDurationMillis = HOURS.toMillis(100);
794
795 long firstOverride = lastEnqueueTimeMillis + HOURS.toMillis(10);
796 long secondOverride = firstOverride + HOURS.toMillis(20);
797 long backoffLinearDurationMillis = MINUTES.toMillis(30);
798
799 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
800 LatchWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
801 .setBackoffCriteria(BackoffPolicy.LINEAR, backoffLinearDurationMillis,
802 TimeUnit.MILLISECONDS)
803 .build();
804
805 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
806 mTestClock.currentTimeMillis = firstOverride;
807 insertWork(periodicWork);
808
809 LatchWorker latchWorker = getLatchWorker(periodicWork, mExecutorService);
810 FutureListener listener = runWorker(periodicWork, latchWorker);
811
812 // Wait for the worker to start, to verify WorkerWrapper got through its initialization
813 latchWorker.mEntrySignal.await();
814
815 // Update the work with a new 'next' runtime while it's already running.
816 WorkSpec inflightWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
817 inflightWorkSpec.setNextScheduleTimeOverride(secondOverride);
818 inflightWorkSpec.setNextScheduleTimeOverrideGeneration(3);
819 mDatabase.workSpecDao().delete(inflightWorkSpec.id);
820 mDatabase.workSpecDao().insertWorkSpec(inflightWorkSpec);
821
822 // Finish the Worker so WorkerWrapper can clean up....
823 latchWorker.mLatch.countDown();
824 listener.mFuture.get();
825
826 // We should still be overridden, even though the worker finished after the override
827 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
828 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(1));
829 assertThat(afterRunWorkSpec.runAttemptCount, equalTo(0));
830 assertThat(afterRunWorkSpec.state, is(ENQUEUED));
831 assertThat(afterRunWorkSpec.getNextScheduleTimeOverrideGeneration(), equalTo(3));
832 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(secondOverride));
833 assertThat(afterRunWorkSpec.calculateNextRunTime(),
834 equalTo(secondOverride));
835 }
836
837 @Test
838 @SmallTest
839 public void testNextScheduleTimeOverride_whileWorkerIsRunning_returnsRetry_usesOverride()
840 throws ExecutionException, InterruptedException {
841 mTestClock.currentTimeMillis = HOURS.toMillis(5);
842 long lastEnqueueTimeMillis = HOURS.toMillis(4);
843 long intervalDurationMillis = HOURS.toMillis(100);
844
845 long firstOverrideMillis = lastEnqueueTimeMillis + HOURS.toMillis(10);
846 long secondOverrideMillis = firstOverrideMillis + HOURS.toMillis(20);
847 long backoffLinearDurationMillis = MINUTES.toMillis(30);
848
849 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
850 LatchWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
851 .setBackoffCriteria(BackoffPolicy.LINEAR, backoffLinearDurationMillis,
852 TimeUnit.MILLISECONDS)
853 .build();
854
855 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
856 mTestClock.currentTimeMillis = firstOverrideMillis;
857 insertWork(periodicWork);
858
859 // Start the worker running
860 LatchWorker latchWorker = getLatchWorker(periodicWork, mExecutorService);
861 latchWorker.returnResult = ListenableWorker.Result.retry();
862 FutureListener listener = runWorker(periodicWork, latchWorker);
863
864 // Wait for the worker to start, to verify WorkerWrapper got through its initialization
865 latchWorker.mEntrySignal.await();
866
867 // Update the work with a new 'next' runtime while it's already running.
868 WorkSpec inflightWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
869 inflightWorkSpec.setNextScheduleTimeOverride(secondOverrideMillis);
870 inflightWorkSpec.setNextScheduleTimeOverrideGeneration(3);
871 mDatabase.workSpecDao().delete(inflightWorkSpec.id);
872 mDatabase.workSpecDao().insertWorkSpec(inflightWorkSpec);
873
874 // Allow the worker to finish
875 latchWorker.mLatch.countDown();
876 listener.mFuture.get();
877
878 // We should still be overridden, even though the worker finished after the override
879 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
880 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(0));
881 // We still write runAttemptCount, etc, so if the override is cleared the 'correct' retry
882 // time is applied based on the actual previous run time.
883 assertThat(afterRunWorkSpec.runAttemptCount, equalTo(1));
884 assertThat(afterRunWorkSpec.state, is(ENQUEUED));
885 assertThat(afterRunWorkSpec.getNextScheduleTimeOverrideGeneration(), equalTo(3));
886 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(secondOverrideMillis));
887 assertThat(afterRunWorkSpec.calculateNextRunTime(),
888 equalTo(secondOverrideMillis));
889 }
890
891 @Test
892 @SmallTest
893 public void testClearNextScheduleTimeOverride_whileWorkerIsRunning_schedulesNextBasedOnEnqueue()
894 throws InterruptedException, ExecutionException {
895 long lastEnqueueTimeMillis = HOURS.toMillis(4);
896 long intervalDurationMillis = HOURS.toMillis(100);
897 long nextScheduleTimeOverrideMillis = lastEnqueueTimeMillis + HOURS.toMillis(10);
898 mTestClock.currentTimeMillis = nextScheduleTimeOverrideMillis;
899
900 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
901 LatchWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
902 .build();
903 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
904 insertWork(periodicWork);
905
906 // Start the worker running
907 LatchWorker latchWorker = getLatchWorker(periodicWork, mExecutorService);
908 latchWorker.returnResult = ListenableWorker.Result.success();
909 FutureListener listener = runWorker(periodicWork, latchWorker);
910
911 // Wait for the worker to start, to verify WorkerWrapper got through its initialization
912 latchWorker.mEntrySignal.await();
913
914 // Update the override generation, but leave the override time to MAX_LONG.
915 // This replicates calling .override(), then .clearOverride() to return /back/ to normal.
916 WorkSpec inflightWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
917 inflightWorkSpec.setNextScheduleTimeOverride(Long.MAX_VALUE);
918 inflightWorkSpec.setNextScheduleTimeOverrideGeneration(5);
919 mDatabase.workSpecDao().delete(inflightWorkSpec.id);
920 mDatabase.workSpecDao().insertWorkSpec(inflightWorkSpec);
921
922 // Allow the worker to finish
923 latchWorker.mLatch.countDown();
924 listener.mFuture.get();
925
926 // We should be scheduled for a "normal" next time, even though overrideGen was changed.
927 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
928 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(1));
929 assertThat(afterRunWorkSpec.runAttemptCount, equalTo(0));
930 assertThat(afterRunWorkSpec.state, is(ENQUEUED));
931 assertThat(afterRunWorkSpec.getNextScheduleTimeOverrideGeneration(), equalTo(5));
932 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(Long.MAX_VALUE));
933 // Normal next period is scheduled.
934 assertThat(afterRunWorkSpec.calculateNextRunTime(),
935 equalTo(mTestClock.currentTimeMillis + intervalDurationMillis));
936 }
937
938
939 @Test
940 @SmallTest
941 public void testClearNextScheduleTimeOverride_whileWorkerIsRunning_schedulesNextBasedOnBackoff()
942 throws InterruptedException, ExecutionException {
943 long lastEnqueueTimeMillis = HOURS.toMillis(4);
944 long intervalDurationMillis = HOURS.toMillis(10);
945 long backoffLinearDurationMillis = HOURS.toMillis(1);
946 long nextScheduleTimeOverrideMillis = lastEnqueueTimeMillis + HOURS.toMillis(2);
947 mTestClock.currentTimeMillis = nextScheduleTimeOverrideMillis;
948
949 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(
950 LatchWorker.class, intervalDurationMillis, TimeUnit.MILLISECONDS)
951 .setBackoffCriteria(BackoffPolicy.LINEAR, backoffLinearDurationMillis,
952 TimeUnit.MILLISECONDS)
953 .build();
954 periodicWork.getWorkSpec().lastEnqueueTime = lastEnqueueTimeMillis;
955 insertWork(periodicWork);
956
957 // Start the worker running
958 LatchWorker latchWorker = getLatchWorker(periodicWork, mExecutorService);
959 latchWorker.returnResult = ListenableWorker.Result.retry();
960 FutureListener listener = runWorker(periodicWork, latchWorker);
961
962 // Wait for the worker to start, to verify WorkerWrapper got through its initialization
963 latchWorker.mEntrySignal.await();
964
965 // Update the override generation, but leave the override time to MAX_LONG.
966 // This replicates calling .override(), then .clearOverride() to return /back/ to normal.
967 WorkSpec inflightWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
968 inflightWorkSpec.setNextScheduleTimeOverride(Long.MAX_VALUE);
969 inflightWorkSpec.setNextScheduleTimeOverrideGeneration(5);
970 mDatabase.workSpecDao().delete(inflightWorkSpec.id);
971 mDatabase.workSpecDao().insertWorkSpec(inflightWorkSpec);
972
973 // Allow the worker to finish
974 latchWorker.mLatch.countDown();
975 listener.mFuture.get();
976
977 // We should be scheduled for a normal backoff, even though overrideGen was changed.
978 WorkSpec afterRunWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
979 assertThat(afterRunWorkSpec.getPeriodCount(), equalTo(0));
980 assertThat(afterRunWorkSpec.runAttemptCount, equalTo(1));
981 assertThat(afterRunWorkSpec.state, is(ENQUEUED));
982 assertThat(afterRunWorkSpec.getNextScheduleTimeOverrideGeneration(), equalTo(5));
983 assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(Long.MAX_VALUE));
984 // Backoff timing is respected
985 assertThat(afterRunWorkSpec.calculateNextRunTime(),
986 equalTo(mTestClock.currentTimeMillis + backoffLinearDurationMillis));
987 }
988
989 @NonNull
990 private FutureListener runWorker(PeriodicWorkRequest periodicWork, Worker worker) {
991 WorkerWrapper workerWrapper =
992 createBuilder(periodicWork.getStringId()).withWorker(worker).build();
993 FutureListener listener = createAndAddFutureListener(workerWrapper);
994 mExecutorService.submit(workerWrapper);
995 return listener;
996 }
997
998 @Test
999 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -07001000 public void testFromWorkSpec_hasAppContext() {
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -07001001 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sumir Kataria931889d2018-10-01 12:44:42 -07001002 ListenableWorker worker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001003 mContext.getApplicationContext(),
1004 TestWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001005 new WorkerParameters(
1006 work.getId(),
1007 Data.EMPTY,
1008 work.getTags(),
1009 new WorkerParameters.RuntimeExtras(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001010 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001011 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001012 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001013 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001014 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001015 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001016 mMockProgressUpdater,
1017 mMockForegroundUpdater));
Sumir Katariada315bf2017-12-06 16:29:10 -08001018
1019 assertThat(worker, is(notNullValue()));
Rahul Ravikumard0d61c52018-04-19 16:52:46 -07001020 assertThat(worker.getApplicationContext(), is(equalTo(mContext.getApplicationContext())));
Sumir Katariada315bf2017-12-06 16:29:10 -08001021 }
1022
1023 @Test
1024 @SmallTest
Sumir Katariadcbf20d2018-04-16 12:40:10 -07001025 public void testFromWorkSpec_hasCorrectArguments() {
Sumir Katariada315bf2017-12-06 16:29:10 -08001026 String key = "KEY";
1027 String expectedValue = "VALUE";
Sumir Kataria64e6bd82018-03-28 17:14:22 -07001028 Data input = new Data.Builder().putString(key, expectedValue).build();
Sumir Katariada315bf2017-12-06 16:29:10 -08001029
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -07001030 OneTimeWorkRequest work =
Sumir Kataria62a7e772018-04-23 21:12:57 -07001031 new OneTimeWorkRequest.Builder(TestWorker.class).setInputData(input).build();
Sumir Kataria931889d2018-10-01 12:44:42 -07001032 ListenableWorker worker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001033 mContext.getApplicationContext(),
1034 TestWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001035 new WorkerParameters(
1036 work.getId(),
1037 input,
1038 work.getTags(),
1039 new WorkerParameters.RuntimeExtras(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001040 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001041 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001042 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001043 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001044 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001045 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001046 mMockProgressUpdater,
1047 mMockForegroundUpdater));
Sumir Katariada315bf2017-12-06 16:29:10 -08001048
1049 assertThat(worker, is(notNullValue()));
Sumir Kataria6d1c4d62018-07-02 12:50:38 -07001050 assertThat(worker.getInputData().getString(key), is(expectedValue));
Sumir Katariada315bf2017-12-06 16:29:10 -08001051
Rahul Ravikumar7031a0f2018-04-19 14:24:30 -07001052 work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sumir Kataria931889d2018-10-01 12:44:42 -07001053 worker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001054 mContext.getApplicationContext(),
1055 TestWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001056 new WorkerParameters(
1057 work.getId(),
1058 Data.EMPTY,
1059 work.getTags(),
1060 new WorkerParameters.RuntimeExtras(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001061 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001062 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001063 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001064 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001065 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001066 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001067 mMockProgressUpdater,
1068 mMockForegroundUpdater));
Sumir Katariada315bf2017-12-06 16:29:10 -08001069
1070 assertThat(worker, is(notNullValue()));
Sumir Kataria64e6bd82018-03-28 17:14:22 -07001071 assertThat(worker.getInputData().size(), is(0));
Sumir Katariada315bf2017-12-06 16:29:10 -08001072 }
Rahul Ravikumar9f91ee82018-03-20 17:33:38 -07001073
1074 @Test
1075 @SmallTest
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001076 public void testFromWorkSpec_hasCorrectTags() {
1077 OneTimeWorkRequest work =
1078 new OneTimeWorkRequest.Builder(TestWorker.class)
1079 .addTag("one")
1080 .addTag("two")
1081 .addTag("three")
1082 .build();
Sumir Kataria931889d2018-10-01 12:44:42 -07001083 ListenableWorker worker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001084 mContext.getApplicationContext(),
1085 TestWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001086 new WorkerParameters(
1087 work.getId(),
1088 Data.EMPTY,
Sumir Katariaa3262882018-08-17 16:15:35 -07001089 Arrays.asList("one", "two", "three"),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001090 new WorkerParameters.RuntimeExtras(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001091 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001092 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001093 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001094 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001095 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001096 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001097 mMockProgressUpdater,
1098 mMockForegroundUpdater));
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001099
1100 assertThat(worker, is(notNullValue()));
1101 assertThat(worker.getTags(), containsInAnyOrder("one", "two", "three"));
1102 }
1103
1104 @Test
1105 @SmallTest
Sergey Vasilinetsdaa87062022-06-21 14:09:49 +01001106 @SdkSuppress(minSdkVersion = 24)
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001107 public void testFromWorkSpec_hasCorrectRuntimeExtras() {
1108 OneTimeWorkRequest work =
1109 new OneTimeWorkRequest.Builder(TestWorker.class).build();
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001110 WorkerParameters.RuntimeExtras runtimeExtras = new WorkerParameters.RuntimeExtras();
Rahul Ravikumarb3a76ba2018-10-12 14:28:06 -07001111 runtimeExtras.triggeredContentAuthorities = Arrays.asList("tca1", "tca2", "tca3");
1112 runtimeExtras.triggeredContentUris = Arrays.asList(Uri.parse("tcu1"), Uri.parse("tcu2"));
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001113
Sumir Kataria931889d2018-10-01 12:44:42 -07001114 ListenableWorker worker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001115 mContext.getApplicationContext(),
1116 TestWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001117 new WorkerParameters(
1118 work.getId(),
1119 Data.EMPTY,
1120 work.getTags(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001121 runtimeExtras,
1122 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001123 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001124 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001125 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001126 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001127 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001128 mMockProgressUpdater,
1129 mMockForegroundUpdater));
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001130
1131 assertThat(worker, is(notNullValue()));
1132 assertThat(worker.getTriggeredContentAuthorities(),
Rahul Ravikumarb3a76ba2018-10-12 14:28:06 -07001133 containsInAnyOrder(runtimeExtras.triggeredContentAuthorities.toArray()));
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001134 assertThat(worker.getTriggeredContentUris(),
Rahul Ravikumarb3a76ba2018-10-12 14:28:06 -07001135 containsInAnyOrder(runtimeExtras.triggeredContentUris.toArray()));
Sumir Kataria7b5c5602018-05-21 15:51:33 -07001136 }
1137
Sergey Vasilinetsafb21272023-06-01 00:00:03 +01001138 // getStopReason() requires API level 31, but only because JobScheduler provides them
1139 // since API level 31, but in this isolated test we don't care.
1140 @SuppressLint("NewApi")
Sumir Kataria5d373d32018-05-30 16:51:36 -07001141 @Test
1142 @SmallTest
Sergey Vasilinetc9d6446d2023-08-16 17:06:29 +01001143 public void testInterruption_isMarkedOnRunningWorker() throws InterruptedException {
Sumir Kataria5d373d32018-05-30 16:51:36 -07001144 OneTimeWorkRequest work =
1145 new OneTimeWorkRequest.Builder(InterruptionAwareWorker.class).build();
1146 insertWork(work);
1147
Sergey Vasilinetc9d6446d2023-08-16 17:06:29 +01001148 InterruptionAwareWorker worker = (InterruptionAwareWorker)
1149 mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001150 mContext.getApplicationContext(),
Sumir Kataria5d373d32018-05-30 16:51:36 -07001151 InterruptionAwareWorker.class.getName(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001152 new WorkerParameters(
1153 work.getId(),
1154 Data.EMPTY,
Sumir Katariaa3262882018-08-17 16:15:35 -07001155 Collections.<String>emptyList(),
Sumir Katariaf82a3d62018-09-12 14:18:23 -07001156 new WorkerParameters.RuntimeExtras(),
Sumir Kataria2cea33c2018-09-07 15:10:39 -07001157 1,
Sergey Vasilinets8e22db32022-08-08 15:39:16 +01001158 0,
Sumir Katariaf7554d2b2018-09-14 13:47:29 -07001159 mSynchronousExecutor,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001160 Dispatchers.getDefault(),
Sumir Kataria9e8b8cc2018-10-01 13:21:12 -07001161 mWorkTaskExecutor,
Rahul Ravikumar05ee9f82019-07-15 10:31:14 -07001162 mConfiguration.getWorkerFactory(),
Rahul Ravikumar3ceb16d2019-10-03 17:20:59 -07001163 mMockProgressUpdater,
1164 mMockForegroundUpdater));
Sumir Kataria5d373d32018-05-30 16:51:36 -07001165 assertThat(worker, is(notNullValue()));
1166 assertThat(worker.isStopped(), is(false));
1167
1168 WorkerWrapper workerWrapper =
Sergey Vasilinets9c84d342022-09-22 11:44:05 +01001169 createBuilder(work.getStringId()).withWorker(worker).build();
Sergey Vasilinets4b07ddb2021-12-16 22:50:01 +00001170 mExecutorService.submit(workerWrapper);
Sergey Vasilinetc9d6446d2023-08-16 17:06:29 +01001171 worker.doWorkLatch.await();
Sergey Vasilinetsafb21272023-06-01 00:00:03 +01001172 workerWrapper.interrupt(STOP_REASON_CONSTRAINT_CHARGING);
Sumir Kataria5d373d32018-05-30 16:51:36 -07001173 assertThat(worker.isStopped(), is(true));
Sergey Vasilinetsafb21272023-06-01 00:00:03 +01001174 assertThat(worker.getStopReason(), is(STOP_REASON_CONSTRAINT_CHARGING));
Rahul Ravikumarb2d24932020-10-08 17:29:31 -07001175 assertThat(mWorkSpecDao.getState(work.getStringId()), is(ENQUEUED));
Sumir Katariabf4f4f72018-05-22 11:23:27 -07001176 }
1177
1178 @Test
1179 @SmallTest
Sumir Kataria3f0c0fb2018-05-07 16:24:48 -07001180 public void testException_isTreatedAsFailure() {
1181 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(ExceptionWorker.class).build();
1182 insertWork(work);
1183
Sergey Vasilinets9c84d342022-09-22 11:44:05 +01001184 createBuilder(work.getStringId()).build().run();
Sumir Kataria3f0c0fb2018-05-07 16:24:48 -07001185
1186 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
1187 }
Sumir Katariad8748112018-05-11 11:22:58 -07001188
1189 @Test
Rahul Ravikumard64fb002018-12-03 13:10:53 -08001190 @SmallTest
1191 public void testWorkerThatReturnsNullResult() {
1192 OneTimeWorkRequest work =
1193 new OneTimeWorkRequest.Builder(ReturnNullResultWorker.class).build();
1194 insertWork(work);
1195 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
1196 FutureListener listener = createAndAddFutureListener(workerWrapper);
1197 workerWrapper.run();
1198 assertThat(listener.mResult, is(false));
1199 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
1200 }
1201
Rahul Ravikumar4d2e0092019-02-20 18:19:43 -08001202 @Test
1203 @SmallTest
1204 public void testWorkerThatThrowsAnException() {
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +00001205 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(ExceptionWorker.class)
1206 .setInputData(new Data.Builder().putString("foo", "bar").build()).build();
Rahul Ravikumar4d2e0092019-02-20 18:19:43 -08001207 insertWork(work);
1208 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
1209 FutureListener listener = createAndAddFutureListener(workerWrapper);
1210 workerWrapper.run();
1211 assertThat(listener.mResult, is(false));
1212 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +00001213 assertThat(mWorkerExceptionHandler.mWorkerClassName,
1214 is("androidx.work.worker.ExceptionWorker"));
1215 assertThat(mWorkerExceptionHandler.mWorkerParameters.getInputData().getString("foo"),
1216 is("bar"));
1217 assertThat(mWorkerExceptionHandler.mThrowable, instanceOf(IllegalStateException.class));
1218 assertThat(mWorkerExceptionHandler.mThrowable.getMessage(), is(
1219 "Thrown in doWork Exception"));
Rahul Ravikumar4d2e0092019-02-20 18:19:43 -08001220 }
1221
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +00001222 @Test
1223 @SmallTest
1224 public void testWorkerThatThrowsAnExceptionInConstruction() {
1225 OneTimeWorkRequest work =
1226 new OneTimeWorkRequest.Builder(ExceptionInConstructionWorker.class)
1227 .setInputData(new Data.Builder().putString("foo", "bar").build()).build();
1228 insertWork(work);
1229 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
1230 FutureListener listener = createAndAddFutureListener(workerWrapper);
1231 workerWrapper.run();
1232 assertThat(listener.mResult, is(false));
1233 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
1234 assertThat(mWorkerExceptionHandler.mWorkerClassName,
1235 is("androidx.work.worker.ExceptionInConstructionWorker"));
1236 assertThat(mWorkerExceptionHandler.mWorkerParameters.getInputData().getString("foo"),
1237 is("bar"));
1238 assertThat(mWorkerExceptionHandler.mThrowable,
1239 is(instanceOf(InvocationTargetException.class)));
1240 Throwable e = ((InvocationTargetException) mWorkerExceptionHandler.mThrowable)
1241 .getTargetException();
1242 assertThat(e, instanceOf(IllegalStateException.class));
1243 assertThat(e.getMessage(), is("Thrown in constructor Exception"));
1244 }
1245
1246 @Test
1247 @SmallTest
Kuan-Ying Chou039d414b2024-01-29 11:43:38 +00001248 public void testCancellationDoesNotTriggerExceptionHandler() {
1249 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(NeverResolvedWorker.class)
1250 .build();
1251 insertWork(work);
1252 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
1253 FutureListener listener = createAndAddFutureListener(workerWrapper);
1254 assertThat(mWorkSpecDao.getState(work.getStringId()), is(ENQUEUED));
1255 workerWrapper.run();
1256 assertThat(mWorkSpecDao.getState(work.getStringId()), is(RUNNING));
1257 workerWrapper.interrupt(0);
1258 assertThat(listener.mResult, is(true));
1259 assertThat(mWorkSpecDao.getState(work.getStringId()), is(ENQUEUED));
1260 assertThat(mWorkerExceptionHandler.mThrowable, nullValue());
1261 }
1262
1263 @Test
1264 @SmallTest
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +00001265 public void testExceptionInWorkerFactory() {
1266 OneTimeWorkRequest work =
1267 new OneTimeWorkRequest.Builder(TestWorker.class)
1268 .setInputData(new Data.Builder().putString("foo", "bar").build()).build();
1269 insertWork(work);
1270 WorkerFactory factory = new WorkerFactory() {
1271 @Nullable
1272 @Override
1273 public ListenableWorker createWorker(@NonNull Context appContext,
1274 @NonNull String workerClassName, @NonNull WorkerParameters workerParameters) {
1275 throw new IllegalStateException("Thrown in WorkerFactory Exception");
1276 }
1277 };
1278 Configuration configuration = new Configuration.Builder(mConfiguration)
1279 .setWorkerFactory(factory)
1280 .build();
1281 WorkerWrapper workerWrapper = new WorkerWrapper.Builder(
1282 mContext,
1283 configuration,
1284 mWorkTaskExecutor,
1285 mMockForegroundProcessor,
1286 mDatabase,
1287 mWorkSpecDao.getWorkSpec(work.getStringId()),
1288 mDatabase.workTagDao().getWorkSpecIdsWithTag(work.getStringId())
1289 ).build();
1290 FutureListener listener = createAndAddFutureListener(workerWrapper);
1291 workerWrapper.run();
1292 assertThat(listener.mResult, is(false));
1293 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
1294 assertThat(mWorkerExceptionHandler.mWorkerClassName,
1295 is("androidx.work.worker.TestWorker"));
1296 assertThat(mWorkerExceptionHandler.mWorkerParameters.getInputData().getString("foo"),
1297 is("bar"));
1298 assertThat(mWorkerExceptionHandler.mThrowable,
1299 is(instanceOf(IllegalStateException.class)));
1300 assertThat(mWorkerExceptionHandler.mThrowable.getMessage(),
1301 is("Thrown in WorkerFactory Exception"));
1302 }
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001303
1304 @SuppressLint("NewApi")
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001305 @Test
Rahul Ravikumar288b32d2019-08-28 09:37:37 -07001306 @MediumTest
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001307 @SdkSuppress(minSdkVersion = 21)
1308 public void testInterruptionsAfterCompletion() {
1309 // Suppressing this test prior to API 21, because creating a spy() ends up loading
1310 // android.net.Network class which does not exist before API 21.
1311
1312 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1313 insertWork(work);
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001314 TrackingWorkerFactory factory = new TrackingWorkerFactory();
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001315 Configuration configuration = new Configuration.Builder(mConfiguration)
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001316 .setWorkerFactory(factory)
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001317 .build();
1318
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001319 String id = work.getStringId();
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001320 WorkerWrapper workerWrapper = new WorkerWrapper.Builder(
1321 mContext,
1322 configuration,
1323 mWorkTaskExecutor,
Rahul Ravikumar15f468c2019-08-30 15:09:02 -07001324 mMockForegroundProcessor,
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001325 mDatabase,
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001326 mWorkSpecDao.getWorkSpec(id),
1327 mDatabase.workTagDao().getTagsForWorkSpecId(id)
Sergey Vasilinets1430b5a2022-06-13 15:03:55 +01001328 ).build();
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001329
1330 FutureListener listener = createAndAddFutureListener(workerWrapper);
1331 workerWrapper.run();
1332 assertThat(listener.mResult, is(false));
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001333 assertThat(mWorkSpecDao.getState(id), is(SUCCEEDED));
Sergey Vasilinetsafb21272023-06-01 00:00:03 +01001334 workerWrapper.interrupt(0);
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001335 ListenableWorker worker = factory.awaitWorker(UUID.fromString(id));
1336 assertThat(worker.getStopReason(), is(WorkInfo.STOP_REASON_NOT_STOPPED));
Rahul Ravikumar74eb3302019-08-27 14:23:43 -07001337 }
1338
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001339 @Test
Rahul Ravikumarae8580f2020-02-27 16:22:21 -08001340 @MediumTest
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001341 @SdkSuppress(minSdkVersion = 21)
1342 public void testInterruptionsBeforeCompletion() {
1343 // Suppressing this test prior to API 21, because creating a spy() ends up loading
1344 // android.net.Network class which does not exist before API 21.
1345
1346 OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
1347 insertWork(work);
1348 // Mark scheduled
1349 mWorkSpecDao.markWorkSpecScheduled(work.getStringId(), System.currentTimeMillis());
1350
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001351 WorkerWrapper workerWrapper = new WorkerWrapper.Builder(
1352 mContext,
Sergey Vasilinetcc333a1c2023-10-19 15:04:25 +01001353 mConfiguration,
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001354 mWorkTaskExecutor,
1355 mMockForegroundProcessor,
1356 mDatabase,
Sergey Vasilinetsbc2bc2a2022-06-29 12:11:20 +01001357 mWorkSpecDao.getWorkSpec(work.getStringId()),
1358 mDatabase.workTagDao().getWorkSpecIdsWithTag(work.getStringId())
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -07001359 ).build();
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001360
Sergey Vasilinetsafb21272023-06-01 00:00:03 +01001361 workerWrapper.interrupt(0);
Rahul Ravikumar3f01efa2020-02-27 15:04:30 -08001362 workerWrapper.run();
1363 WorkSpec workSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
1364 assertThat(workSpec.scheduleRequestedAt, is(-1L));
1365 }
1366
Rahul Ravikumarced3e7c2020-05-27 15:39:56 -07001367 @Test
1368 @SmallTest
1369 public void testWorkRequest_withInvalidClassName() {
1370 OneTimeWorkRequest work =
1371 new OneTimeWorkRequest.Builder(TestWorker.class).build();
1372 work.getWorkSpec().workerClassName = "Bad class name";
1373 insertWork(work);
1374 WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
1375 workerWrapper.run();
1376 assertThat(mWorkSpecDao.getState(work.getStringId()), is(FAILED));
1377 }
1378
Sumir Kataria8df18fe2018-08-23 10:19:02 -07001379 private WorkerWrapper.Builder createBuilder(String workSpecId) {
1380 return new WorkerWrapper.Builder(
1381 mContext,
1382 mConfiguration,
1383 mWorkTaskExecutor,
Rahul Ravikumar15f468c2019-08-30 15:09:02 -07001384 mMockForegroundProcessor,
Sumir Kataria8df18fe2018-08-23 10:19:02 -07001385 mDatabase,
Sergey Vasilinetsbc2bc2a2022-06-29 12:11:20 +01001386 mWorkSpecDao.getWorkSpec(workSpecId),
1387 mDatabase.workTagDao().getWorkSpecIdsWithTag(workSpecId)
1388 );
Sumir Kataria8df18fe2018-08-23 10:19:02 -07001389 }
Sumir Kataria0c320a82018-09-06 16:20:53 -07001390
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -07001391 @Nullable
1392 private LatchWorker getLatchWorker(WorkRequest work) {
1393 return getLatchWorker(work, mExecutorService);
1394 }
1395
1396 @Nullable
1397 private LatchWorker getLatchWorker(WorkRequest work, ExecutorService executorService) {
1398 return (LatchWorker) mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
1399 mContext.getApplicationContext(),
1400 LatchWorker.class.getName(),
1401 new WorkerParameters(
1402 work.getId(),
1403 Data.EMPTY,
1404 work.getTags(),
1405 new WorkerParameters.RuntimeExtras(),
1406 1,
1407 0,
1408 executorService,
Sergey Vasilinetce46854a2024-02-07 16:45:34 +00001409 Dispatchers.getDefault(),
Faelyn O'Grady1560dcf2023-03-27 16:13:05 -07001410 mWorkTaskExecutor,
1411 mConfiguration.getWorkerFactory(),
1412 mMockProgressUpdater,
1413 mMockForegroundUpdater));
1414 }
1415
Sumir Kataria0c320a82018-09-06 16:20:53 -07001416 private FutureListener createAndAddFutureListener(WorkerWrapper workerWrapper) {
1417 ListenableFuture<Boolean> future = workerWrapper.getFuture();
1418 FutureListener listener = new FutureListener(future);
1419 future.addListener(listener, mSynchronousExecutor);
1420 return listener;
1421 }
1422
1423 private static class FutureListener implements Runnable {
1424
1425 ListenableFuture<Boolean> mFuture;
1426 Boolean mResult;
1427
1428 FutureListener(ListenableFuture<Boolean> future) {
1429 mFuture = future;
1430 }
1431
1432 @Override
1433 public void run() {
1434 try {
1435 mResult = mFuture.get();
1436 } catch (InterruptedException | ExecutionException e) {
1437 // Do nothing.
1438 }
1439 }
1440 }
Kuan-Ying Chou4bdf3212024-01-09 16:43:41 +00001441
1442 private static class TestWorkerExceptionHandler implements Consumer<WorkerExceptionInfo> {
1443 String mWorkerClassName;
1444 WorkerParameters mWorkerParameters;
1445 Throwable mThrowable;
1446
1447 @Override
1448 public void accept(WorkerExceptionInfo params) {
1449 this.mWorkerClassName = params.getWorkerClassName();
1450 this.mWorkerParameters = params.getWorkerParameters();
1451 this.mThrowable = params.getThrowable();
1452 }
1453 };
Xyan Bhatnagarb8909f22017-09-20 15:45:56 -07001454}