WorkManagerImplTest.java revision 3665b829af9706f7f85c53e4ef5a0825228f4d7a
1/* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.work.impl; 18 19import static org.hamcrest.CoreMatchers.is; 20import static org.hamcrest.CoreMatchers.not; 21import static org.hamcrest.CoreMatchers.notNullValue; 22import static org.hamcrest.CoreMatchers.nullValue; 23import static org.hamcrest.MatcherAssert.assertThat; 24import static org.hamcrest.Matchers.containsInAnyOrder; 25import static org.hamcrest.Matchers.emptyCollectionOf; 26import static org.hamcrest.Matchers.greaterThanOrEqualTo; 27import static org.hamcrest.Matchers.isIn; 28import static org.hamcrest.Matchers.isOneOf; 29import static org.mockito.Mockito.clearInvocations; 30import static org.mockito.Mockito.mock; 31import static org.mockito.Mockito.times; 32import static org.mockito.Mockito.verify; 33 34import static androidx.work.ExistingWorkPolicy.APPEND; 35import static androidx.work.ExistingWorkPolicy.KEEP; 36import static androidx.work.ExistingWorkPolicy.REPLACE; 37import static androidx.work.NetworkType.METERED; 38import static androidx.work.NetworkType.NOT_REQUIRED; 39import static androidx.work.State.BLOCKED; 40import static androidx.work.State.CANCELLED; 41import static androidx.work.State.ENQUEUED; 42import static androidx.work.State.FAILED; 43import static androidx.work.State.RUNNING; 44import static androidx.work.State.SUCCEEDED; 45 46import android.arch.core.executor.ArchTaskExecutor; 47import android.arch.core.executor.TaskExecutor; 48import android.arch.lifecycle.LiveData; 49import android.arch.lifecycle.Observer; 50import android.arch.persistence.db.SupportSQLiteDatabase; 51import android.arch.persistence.db.SupportSQLiteOpenHelper; 52import android.content.Context; 53import android.net.Uri; 54import android.os.Build; 55import android.provider.MediaStore; 56import android.support.annotation.NonNull; 57import android.support.test.InstrumentationRegistry; 58import android.support.test.filters.SdkSuppress; 59import android.support.test.filters.SmallTest; 60import android.support.test.runner.AndroidJUnit4; 61 62import org.junit.After; 63import org.junit.Before; 64import org.junit.Rule; 65import org.junit.Test; 66import org.junit.runner.RunWith; 67import org.mockito.ArgumentCaptor; 68 69import java.util.Arrays; 70import java.util.Collections; 71import java.util.List; 72import java.util.concurrent.Executors; 73import java.util.concurrent.TimeUnit; 74 75import androidx.work.Arguments; 76import androidx.work.BackoffPolicy; 77import androidx.work.BaseWork; 78import androidx.work.Constraints; 79import androidx.work.ContentUriTriggers; 80import androidx.work.PeriodicWork; 81import androidx.work.TestLifecycleOwner; 82import androidx.work.Work; 83import androidx.work.WorkContinuation; 84import androidx.work.WorkManagerTest; 85import androidx.work.WorkStatus; 86import androidx.work.impl.model.Dependency; 87import androidx.work.impl.model.DependencyDao; 88import androidx.work.impl.model.WorkSpec; 89import androidx.work.impl.model.WorkSpecDao; 90import androidx.work.impl.model.WorkTag; 91import androidx.work.impl.model.WorkTagDao; 92import androidx.work.impl.utils.taskexecutor.InstantTaskExecutorRule; 93import androidx.work.worker.InfiniteTestWorker; 94import androidx.work.worker.TestWorker; 95 96@RunWith(AndroidJUnit4.class) 97public class WorkManagerImplTest extends WorkManagerTest { 98 private WorkDatabase mDatabase; 99 private WorkManagerImpl mWorkManagerImpl; 100 101 @Rule 102 public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule(); 103 104 @Before 105 public void setUp() { 106 ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() { 107 @Override 108 public void executeOnDiskIO(@NonNull Runnable runnable) { 109 runnable.run(); 110 } 111 112 @Override 113 public void postToMainThread(@NonNull Runnable runnable) { 114 runnable.run(); 115 } 116 117 @Override 118 public boolean isMainThread() { 119 return true; 120 } 121 }); 122 123 Context context = InstrumentationRegistry.getTargetContext(); 124 WorkManagerConfiguration configuration = new WorkManagerConfiguration( 125 context, 126 true, 127 Executors.newSingleThreadExecutor()); 128 mWorkManagerImpl = new WorkManagerImpl(context, configuration); 129 mDatabase = mWorkManagerImpl.getWorkDatabase(); 130 } 131 132 @After 133 public void tearDown() { 134 List<String> ids = mDatabase.workSpecDao().getAllWorkSpecIds(); 135 for (String id : ids) { 136 mWorkManagerImpl.cancelWorkById(id); 137 } 138 mDatabase.close(); 139 ArchTaskExecutor.getInstance().setDelegate(null); 140 } 141 142 @Test 143 @SmallTest 144 public void testEnqueue_insertWork() throws InterruptedException { 145 final int workCount = 3; 146 final Work[] workArray = new Work[workCount]; 147 for (int i = 0; i < workCount; ++i) { 148 workArray[i] = new Work.Builder(TestWorker.class).build(); 149 } 150 mWorkManagerImpl.beginWith(workArray[0]).then(workArray[1]).then(workArray[2]).enqueue(); 151 152 for (int i = 0; i < workCount; ++i) { 153 String id = workArray[i].getId(); 154 assertThat(mDatabase.workSpecDao().getWorkSpec(id), is(notNullValue())); 155 assertThat( 156 "index " + i + " does not have expected number of dependencies!", 157 mDatabase.dependencyDao().getPrerequisites(id).size() > 0, 158 is(i > 0)); 159 } 160 } 161 162 @Test 163 @SmallTest 164 public void testEnqueue_insertMultipleWork() { 165 Work work1 = new Work.Builder(TestWorker.class).build(); 166 Work work2 = new Work.Builder(TestWorker.class).build(); 167 Work work3 = new Work.Builder(TestWorker.class).build(); 168 169 mWorkManagerImpl.enqueue(work1, work2, work3); 170 171 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 172 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(notNullValue())); 173 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(notNullValue())); 174 assertThat(workSpecDao.getWorkSpec(work3.getId()), is(notNullValue())); 175 } 176 177 @Test 178 @SmallTest 179 public void testEnqueue_insertWithDependencies() { 180 Work work1a = new Work.Builder(TestWorker.class).build(); 181 Work work1b = new Work.Builder(TestWorker.class).build(); 182 Work work2 = new Work.Builder(TestWorker.class).build(); 183 Work work3a = new Work.Builder(TestWorker.class).build(); 184 Work work3b = new Work.Builder(TestWorker.class).build(); 185 186 mWorkManagerImpl.beginWith(work1a, work1b).then(work2).then(work3a, work3b).enqueue(); 187 188 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 189 assertThat(workSpecDao.getWorkSpec(work1a.getId()), is(notNullValue())); 190 assertThat(workSpecDao.getWorkSpec(work1b.getId()), is(notNullValue())); 191 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(notNullValue())); 192 assertThat(workSpecDao.getWorkSpec(work3a.getId()), is(notNullValue())); 193 assertThat(workSpecDao.getWorkSpec(work3b.getId()), is(notNullValue())); 194 195 DependencyDao dependencyDao = mDatabase.dependencyDao(); 196 assertThat(dependencyDao.getPrerequisites(work1a.getId()), 197 is(emptyCollectionOf(String.class))); 198 assertThat(dependencyDao.getPrerequisites(work1b.getId()), 199 is(emptyCollectionOf(String.class))); 200 201 List<String> prerequisites = dependencyDao.getPrerequisites(work2.getId()); 202 assertThat(prerequisites, containsInAnyOrder(work1a.getId(), work1b.getId())); 203 204 prerequisites = dependencyDao.getPrerequisites(work3a.getId()); 205 assertThat(prerequisites, containsInAnyOrder(work2.getId())); 206 207 prerequisites = dependencyDao.getPrerequisites(work3b.getId()); 208 assertThat(prerequisites, containsInAnyOrder(work2.getId())); 209 } 210 211 @Test 212 @SmallTest 213 public void testEnqueue_insertWithCompletedDependencies_isNotStatusBlocked() { 214 Work work1 = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 215 216 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 217 workContinuation.enqueue(); 218 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 219 assertThat(workSpecDao.getState(work1.getId()), is(SUCCEEDED)); 220 221 Work work2 = new Work.Builder(InfiniteTestWorker.class).build(); 222 workContinuation.then(work2).enqueue(); 223 assertThat(workSpecDao.getState(work2.getId()), isOneOf(ENQUEUED, RUNNING)); 224 } 225 226 @Test 227 @SmallTest 228 public void testEnqueue_insertWithFailedDependencies_isStatusFailed() { 229 Work work1 = new Work.Builder(TestWorker.class).withInitialState(FAILED).build(); 230 231 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 232 workContinuation.enqueue(); 233 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 234 assertThat(workSpecDao.getState(work1.getId()), is(FAILED)); 235 236 Work work2 = new Work.Builder(TestWorker.class).build(); 237 workContinuation.then(work2).enqueue(); 238 assertThat(workSpecDao.getState(work2.getId()), is(FAILED)); 239 } 240 241 @Test 242 @SmallTest 243 public void testEnqueue_insertWithCancelledDependencies_isStatusCancelled() { 244 Work work1 = new Work.Builder(TestWorker.class).withInitialState(CANCELLED).build(); 245 246 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 247 workContinuation.enqueue(); 248 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 249 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 250 251 Work work2 = new Work.Builder(TestWorker.class).build(); 252 workContinuation.then(work2).enqueue(); 253 assertThat(workSpecDao.getState(work2.getId()), is(CANCELLED)); 254 } 255 256 @Test 257 @SmallTest 258 @SdkSuppress(minSdkVersion = 23) 259 public void testEnqueue_insertWorkConstraints() { 260 Uri testUri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 261 Uri testUri2 = MediaStore.Images.Media.INTERNAL_CONTENT_URI; 262 263 Work work0 = new Work.Builder(TestWorker.class) 264 .withConstraints( 265 new Constraints.Builder() 266 .setRequiresCharging(true) 267 .setRequiresDeviceIdle(true) 268 .setRequiredNetworkType(METERED) 269 .setRequiresBatteryNotLow(true) 270 .setRequiresStorageNotLow(true) 271 .addContentUriTrigger(testUri1, true) 272 .addContentUriTrigger(testUri2, false) 273 .build()) 274 .build(); 275 Work work1 = new Work.Builder(TestWorker.class).build(); 276 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 277 278 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 279 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 280 281 ContentUriTriggers expectedTriggers = new ContentUriTriggers(); 282 expectedTriggers.add(testUri1, true); 283 expectedTriggers.add(testUri2, false); 284 285 Constraints constraints = workSpec0.getConstraints(); 286 assertThat(constraints, is(notNullValue())); 287 assertThat(constraints.requiresCharging(), is(true)); 288 assertThat(constraints.requiresDeviceIdle(), is(true)); 289 assertThat(constraints.requiresBatteryNotLow(), is(true)); 290 assertThat(constraints.requiresStorageNotLow(), is(true)); 291 assertThat(constraints.getRequiredNetworkType(), is(METERED)); 292 if (Build.VERSION.SDK_INT >= 24) { 293 assertThat(constraints.getContentUriTriggers(), is(expectedTriggers)); 294 } else { 295 assertThat(constraints.getContentUriTriggers(), is(new ContentUriTriggers())); 296 } 297 298 constraints = workSpec1.getConstraints(); 299 assertThat(constraints, is(notNullValue())); 300 assertThat(constraints.requiresCharging(), is(false)); 301 assertThat(constraints.requiresDeviceIdle(), is(false)); 302 assertThat(constraints.requiresBatteryNotLow(), is(false)); 303 assertThat(constraints.requiresStorageNotLow(), is(false)); 304 assertThat(constraints.getRequiredNetworkType(), is(NOT_REQUIRED)); 305 assertThat(constraints.getContentUriTriggers().size(), is(0)); 306 } 307 308 @Test 309 @SmallTest 310 public void testEnqueue_insertWorkInitialDelay() { 311 final long expectedInitialDelay = 5000L; 312 Work work0 = new Work.Builder(TestWorker.class) 313 .withInitialDelay(expectedInitialDelay, TimeUnit.MILLISECONDS) 314 .build(); 315 Work work1 = new Work.Builder(TestWorker.class).build(); 316 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 317 318 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 319 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 320 321 assertThat(workSpec0.getInitialDelay(), is(expectedInitialDelay)); 322 assertThat(workSpec1.getInitialDelay(), is(0L)); 323 } 324 325 @Test 326 @SmallTest 327 public void testEnqueue_insertWorkBackoffPolicy() { 328 Work work0 = new Work.Builder(TestWorker.class) 329 .withBackoffCriteria(BackoffPolicy.LINEAR, 50000, TimeUnit.MILLISECONDS) 330 .build(); 331 Work work1 = new Work.Builder(TestWorker.class).build(); 332 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 333 334 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 335 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 336 337 assertThat(workSpec0.getBackoffPolicy(), is(BackoffPolicy.LINEAR)); 338 assertThat(workSpec0.getBackoffDelayDuration(), is(50000L)); 339 340 assertThat(workSpec1.getBackoffPolicy(), is(BackoffPolicy.EXPONENTIAL)); 341 assertThat(workSpec1.getBackoffDelayDuration(), is(BaseWork.DEFAULT_BACKOFF_DELAY_MILLIS)); 342 } 343 344 @Test 345 @SmallTest 346 public void testEnqueue_insertWorkTags() { 347 final String firstTag = "first_tag"; 348 final String secondTag = "second_tag"; 349 final String thirdTag = "third_tag"; 350 351 Work work0 = new Work.Builder(TestWorker.class).addTag(firstTag).addTag(secondTag).build(); 352 Work work1 = new Work.Builder(TestWorker.class).addTag(firstTag).build(); 353 Work work2 = new Work.Builder(TestWorker.class).build(); 354 mWorkManagerImpl.beginWith(work0).then(work1).then(work2).enqueue(); 355 356 WorkTagDao workTagDao = mDatabase.workTagDao(); 357 assertThat(workTagDao.getWorkSpecIdsWithTag(firstTag), 358 containsInAnyOrder(work0.getId(), work1.getId())); 359 assertThat(workTagDao.getWorkSpecIdsWithTag(secondTag), containsInAnyOrder(work0.getId())); 360 assertThat(workTagDao.getWorkSpecIdsWithTag(thirdTag), emptyCollectionOf(String.class)); 361 } 362 363 @Test 364 @SmallTest 365 public void testEnqueue_insertPeriodicWork() { 366 PeriodicWork periodicWork = new PeriodicWork.Builder( 367 TestWorker.class, 368 PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS, 369 TimeUnit.MILLISECONDS) 370 .build(); 371 mWorkManagerImpl.enqueue(periodicWork); 372 373 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getId()); 374 assertThat(workSpec.isPeriodic(), is(true)); 375 assertThat(workSpec.getIntervalDuration(), is(PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS)); 376 assertThat(workSpec.getFlexDuration(), is(PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS)); 377 } 378 379 @Test 380 @SmallTest 381 public void testEnqueued_work_setsPeriodStartTime() { 382 Work work = new Work.Builder(TestWorker.class).build(); 383 assertThat(getWorkSpec(work).getPeriodStartTime(), is(0L)); 384 385 long beforeEnqueueTime = System.currentTimeMillis(); 386 387 mWorkManagerImpl.enqueue(work); 388 389 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getId()); 390 assertThat(workSpec.getPeriodStartTime(), is(greaterThanOrEqualTo(beforeEnqueueTime))); 391 } 392 393 @Test 394 @SmallTest 395 public void testEnqueued_periodicWork_setsPeriodStartTime() { 396 PeriodicWork periodicWork = new PeriodicWork.Builder( 397 TestWorker.class, 398 PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS, 399 TimeUnit.MILLISECONDS) 400 .build(); 401 assertThat(getWorkSpec(periodicWork).getPeriodStartTime(), is(0L)); 402 403 long beforeEnqueueTime = System.currentTimeMillis(); 404 405 mWorkManagerImpl.enqueue(periodicWork); 406 407 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getId()); 408 assertThat(workSpec.getPeriodStartTime(), is(greaterThanOrEqualTo(beforeEnqueueTime))); 409 } 410 411 @Test 412 @SmallTest 413 public void testBeginWithName_setsUniqueName() { 414 final String testName = "myname"; 415 416 Work work = new Work.Builder(TestWorker.class).build(); 417 mWorkManagerImpl.beginWithName(testName, REPLACE) 418 .then(work) 419 .enqueue(); 420 421 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 422 assertThat(work.getId(), isIn(workSpecIds)); 423 } 424 425 @Test 426 @SmallTest 427 public void testBeginWithName_deletesOldWorkOnReplace() { 428 final String testName = "myname"; 429 430 Work originalWork = new Work.Builder(InfiniteTestWorker.class).build(); 431 mWorkManagerImpl.beginWithName(testName, KEEP, originalWork).enqueue(); 432 433 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 434 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 435 436 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 437 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 438 mWorkManagerImpl 439 .beginWithName(testName, REPLACE, replacementWork1) 440 .then(replacementWork2) 441 .enqueue(); 442 443 workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 444 assertThat( 445 workSpecIds, 446 containsInAnyOrder(replacementWork1.getId(), replacementWork2.getId())); 447 448 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 449 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(nullValue())); 450 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(not(nullValue()))); 451 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(not(nullValue()))); 452 } 453 454 @Test 455 @SmallTest 456 public void testBeginWithName_keepsExistingWorkOnKeep() { 457 final String testName = "myname"; 458 459 Work originalWork = new Work.Builder(InfiniteTestWorker.class).build(); 460 mWorkManagerImpl.beginWithName(testName, KEEP, originalWork).enqueue(); 461 462 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 463 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 464 465 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 466 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 467 mWorkManagerImpl 468 .beginWithName(testName, KEEP, replacementWork1) 469 .then(replacementWork2) 470 .enqueue(); 471 472 workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 473 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 474 475 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 476 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(not(nullValue()))); 477 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(nullValue())); 478 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(nullValue())); 479 } 480 481 @Test 482 @SmallTest 483 public void testBeginWithName_replacesExistingWorkOnKeepWhenExistingWorkIsFinished() { 484 final String testName = "myname"; 485 486 Work originalWork = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 487 mWorkManagerImpl.beginWithName(testName, KEEP, originalWork).enqueue(); 488 489 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 490 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 491 492 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 493 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 494 mWorkManagerImpl 495 .beginWithName(testName, KEEP, replacementWork1) 496 .then(replacementWork2) 497 .enqueue(); 498 499 workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 500 assertThat(workSpecIds, 501 containsInAnyOrder(replacementWork1.getId(), replacementWork2.getId())); 502 503 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 504 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(nullValue())); 505 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(not(nullValue()))); 506 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(not(nullValue()))); 507 } 508 509 @Test 510 @SmallTest 511 public void testBeginWithName_appendsExistingWorkOnAppend() { 512 final String testName = "myname"; 513 514 Work originalWork = new Work.Builder(InfiniteTestWorker.class).build(); 515 mWorkManagerImpl.beginWithName(testName, KEEP, originalWork).enqueue(); 516 517 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 518 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 519 520 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 521 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 522 mWorkManagerImpl 523 .beginWithName(testName, APPEND, appendWork1) 524 .then(appendWork2) 525 .enqueue(); 526 527 workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 528 assertThat(workSpecIds, 529 containsInAnyOrder(originalWork.getId(), appendWork1.getId(), appendWork2.getId())); 530 531 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 532 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(not(nullValue()))); 533 assertThat(workSpecDao.getState(appendWork1.getId()), is(BLOCKED)); 534 assertThat(workSpecDao.getState(appendWork2.getId()), is(BLOCKED)); 535 536 assertThat(mDatabase.dependencyDao().getDependentWorkIds(originalWork.getId()), 537 containsInAnyOrder(appendWork1.getId())); 538 } 539 540 @Test 541 @SmallTest 542 public void testBeginWithName_appendsExistingWorkToOnlyLeavesOnAppend() { 543 final String testName = "myname"; 544 545 Work originalWork1 = new Work.Builder(InfiniteTestWorker.class).build(); 546 Work originalWork2 = new Work.Builder(InfiniteTestWorker.class).build(); 547 Work originalWork3 = new Work.Builder(InfiniteTestWorker.class).build(); 548 Work originalWork4 = new Work.Builder(InfiniteTestWorker.class).build(); 549 mWorkManagerImpl.beginWithName(testName, KEEP, originalWork1) 550 .then(originalWork2) 551 .then(originalWork3, originalWork4) 552 .enqueue(); 553 554 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 555 assertThat(workSpecIds, 556 containsInAnyOrder( 557 originalWork1.getId(), 558 originalWork2.getId(), 559 originalWork3.getId(), 560 originalWork4.getId())); 561 562 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 563 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 564 mWorkManagerImpl 565 .beginWithName(testName, APPEND, appendWork1) 566 .then(appendWork2) 567 .enqueue(); 568 569 workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 570 assertThat(workSpecIds, 571 containsInAnyOrder( 572 originalWork1.getId(), 573 originalWork2.getId(), 574 originalWork3.getId(), 575 originalWork4.getId(), 576 appendWork1.getId(), 577 appendWork2.getId())); 578 579 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 580 assertThat(workSpecDao.getWorkSpec(originalWork1.getId()), is(not(nullValue()))); 581 assertThat(workSpecDao.getWorkSpec(originalWork2.getId()), is(not(nullValue()))); 582 assertThat(workSpecDao.getWorkSpec(originalWork3.getId()), is(not(nullValue()))); 583 assertThat(workSpecDao.getWorkSpec(originalWork4.getId()), is(not(nullValue()))); 584 assertThat(workSpecDao.getState(appendWork1.getId()), is(BLOCKED)); 585 assertThat(workSpecDao.getState(appendWork2.getId()), is(BLOCKED)); 586 587 DependencyDao dependencyDao = mDatabase.dependencyDao(); 588 assertThat(dependencyDao.getPrerequisites(appendWork1.getId()), 589 containsInAnyOrder(originalWork3.getId(), originalWork4.getId())); 590 assertThat(dependencyDao.getPrerequisites(appendWork2.getId()), 591 containsInAnyOrder(appendWork1.getId())); 592 } 593 594 @Test 595 @SmallTest 596 public void testBeginWithName_insertsExistingWorkWhenNothingToAppendTo() { 597 final String testName = "myname"; 598 599 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 600 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 601 mWorkManagerImpl 602 .beginWithName(testName, APPEND, appendWork1) 603 .then(appendWork2) 604 .enqueue(); 605 606 List<String> workSpecIds = mDatabase.workNameDao().getWorkSpecIdsWithName(testName); 607 assertThat(workSpecIds, 608 containsInAnyOrder(appendWork1.getId(), appendWork2.getId())); 609 } 610 611 @Test 612 @SmallTest 613 public void testGetStatusByIdSync() { 614 Work work = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 615 insertWorkSpecAndTags(work); 616 617 WorkStatus workStatus = mWorkManagerImpl.getStatusByIdBlocking(work.getId()); 618 assertThat(workStatus.getId(), is(work.getId())); 619 assertThat(workStatus.getState(), is(SUCCEEDED)); 620 } 621 622 @Test 623 @SmallTest 624 public void testGetStatusByIdSync_returnsNullIfNotInDatabase() { 625 WorkStatus workStatus = mWorkManagerImpl.getStatusByIdBlocking("dummy"); 626 assertThat(workStatus, is(nullValue())); 627 } 628 629 @Test 630 @SmallTest 631 @SuppressWarnings("unchecked") 632 public void testGetStatusesById() { 633 Work work0 = new Work.Builder(TestWorker.class).build(); 634 Work work1 = new Work.Builder(TestWorker.class).build(); 635 insertWorkSpecAndTags(work0); 636 insertWorkSpecAndTags(work1); 637 638 Observer<List<WorkStatus>> mockObserver = mock(Observer.class); 639 640 TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner(); 641 LiveData<List<WorkStatus>> liveData = 642 mWorkManagerImpl.getStatusesById(Arrays.asList(work0.getId(), work1.getId())); 643 liveData.observe(testLifecycleOwner, mockObserver); 644 645 ArgumentCaptor<List<WorkStatus>> captor = 646 ArgumentCaptor.forClass(List.class); 647 verify(mockObserver).onChanged(captor.capture()); 648 assertThat(captor.getValue(), is(not(nullValue()))); 649 assertThat(captor.getValue().size(), is(2)); 650 651 WorkStatus workStatus0 = new WorkStatus( 652 work0.getId(), 653 ENQUEUED, 654 Arguments.EMPTY, 655 Collections.<String>emptyList()); 656 WorkStatus workStatus1 = new WorkStatus( 657 work1.getId(), 658 ENQUEUED, 659 Arguments.EMPTY, 660 Collections.<String>emptyList()); 661 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 662 663 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 664 workSpecDao.setState(RUNNING, work0.getId()); 665 666 verify(mockObserver, times(2)).onChanged(captor.capture()); 667 assertThat(captor.getValue(), is(not(nullValue()))); 668 assertThat(captor.getValue().size(), is(2)); 669 670 workStatus0 = new WorkStatus( 671 work0.getId(), 672 RUNNING, 673 Arguments.EMPTY, 674 Collections.<String>emptyList()); 675 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 676 677 clearInvocations(mockObserver); 678 workSpecDao.setState(RUNNING, work1.getId()); 679 680 verify(mockObserver).onChanged(captor.capture()); 681 assertThat(captor.getValue(), is(not(nullValue()))); 682 assertThat(captor.getValue().size(), is(2)); 683 684 workStatus1 = new WorkStatus( 685 work1.getId(), 686 RUNNING, 687 Arguments.EMPTY, 688 Collections.<String>emptyList()); 689 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 690 691 liveData.removeObservers(testLifecycleOwner); 692 } 693 694 @Test 695 @SmallTest 696 public void testGetStatusesByTagSync() { 697 final String firstTag = "first_tag"; 698 final String secondTag = "second_tag"; 699 700 Work work0 = new Work.Builder(TestWorker.class) 701 .addTag(firstTag) 702 .addTag(secondTag) 703 .withInitialState(RUNNING) 704 .build(); 705 Work work1 = new Work.Builder(TestWorker.class) 706 .addTag(firstTag) 707 .withInitialState(BLOCKED) 708 .build(); 709 Work work2 = new Work.Builder(TestWorker.class) 710 .addTag(secondTag) 711 .withInitialState(SUCCEEDED) 712 .build(); 713 insertWorkSpecAndTags(work0); 714 insertWorkSpecAndTags(work1); 715 insertWorkSpecAndTags(work2); 716 717 WorkStatus workStatus0 = new WorkStatus( 718 work0.getId(), 719 RUNNING, 720 Arguments.EMPTY, 721 Arrays.asList(firstTag, secondTag)); 722 WorkStatus workStatus1 = new WorkStatus( 723 work1.getId(), 724 BLOCKED, 725 Arguments.EMPTY, 726 Collections.singletonList(firstTag)); 727 WorkStatus workStatus2 = new WorkStatus( 728 work2.getId(), 729 SUCCEEDED, 730 Arguments.EMPTY, 731 Collections.singletonList(secondTag)); 732 733 List<WorkStatus> workStatuses = mWorkManagerImpl.getStatusesByTagBlocking(firstTag); 734 assertThat(workStatuses, containsInAnyOrder(workStatus0, workStatus1)); 735 736 workStatuses = mWorkManagerImpl.getStatusesByTagBlocking(secondTag); 737 assertThat(workStatuses, containsInAnyOrder(workStatus0, workStatus2)); 738 739 workStatuses = mWorkManagerImpl.getStatusesByTagBlocking("dummy"); 740 assertThat(workStatuses.size(), is(0)); 741 } 742 743 @Test 744 @SmallTest 745 @SuppressWarnings("unchecked") 746 public void testGetStatusesByTag() { 747 final String firstTag = "first_tag"; 748 final String secondTag = "second_tag"; 749 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 750 751 Work work0 = new Work.Builder(TestWorker.class) 752 .addTag(firstTag) 753 .addTag(secondTag) 754 .withInitialState(RUNNING) 755 .build(); 756 Work work1 = new Work.Builder(TestWorker.class) 757 .addTag(firstTag) 758 .withInitialState(BLOCKED) 759 .build(); 760 Work work2 = new Work.Builder(TestWorker.class) 761 .addTag(secondTag) 762 .withInitialState(SUCCEEDED) 763 .build(); 764 insertWorkSpecAndTags(work0); 765 insertWorkSpecAndTags(work1); 766 insertWorkSpecAndTags(work2); 767 768 Observer<List<WorkStatus>> mockObserver = mock(Observer.class); 769 770 TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner(); 771 LiveData<List<WorkStatus>> liveData = 772 mWorkManagerImpl.getStatusesByTag(firstTag); 773 liveData.observe(testLifecycleOwner, mockObserver); 774 775 ArgumentCaptor<List<WorkStatus>> captor = 776 ArgumentCaptor.forClass(List.class); 777 verify(mockObserver).onChanged(captor.capture()); 778 assertThat(captor.getValue(), is(not(nullValue()))); 779 assertThat(captor.getValue().size(), is(2)); 780 781 WorkStatus workStatus0 = new WorkStatus( 782 work0.getId(), 783 RUNNING, 784 Arguments.EMPTY, 785 Arrays.asList(firstTag, secondTag)); 786 WorkStatus workStatus1 = new WorkStatus( 787 work1.getId(), 788 BLOCKED, 789 Arguments.EMPTY, 790 Collections.singletonList(firstTag)); 791 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 792 793 workSpecDao.setState(ENQUEUED, work0.getId()); 794 795 verify(mockObserver, times(2)).onChanged(captor.capture()); 796 assertThat(captor.getValue(), is(not(nullValue()))); 797 assertThat(captor.getValue().size(), is(2)); 798 799 workStatus0 = new WorkStatus( 800 work0.getId(), 801 ENQUEUED, 802 Arguments.EMPTY, 803 Arrays.asList(firstTag, secondTag)); 804 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 805 806 liveData.removeObservers(testLifecycleOwner); 807 } 808 809 @Test 810 @SmallTest 811 public void testCancelWorkForId() { 812 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 813 814 Work work0 = new Work.Builder(TestWorker.class).build(); 815 Work work1 = new Work.Builder(TestWorker.class).build(); 816 insertWorkSpecAndTags(work0); 817 insertWorkSpecAndTags(work1); 818 819 mWorkManagerImpl.cancelWorkById(work0.getId()); 820 821 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 822 assertThat(workSpecDao.getState(work1.getId()), is(not(CANCELLED))); 823 } 824 825 @Test 826 @SmallTest 827 public void testCancelWorkForId_cancelsDependentWork() { 828 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 829 830 Work work0 = new Work.Builder(TestWorker.class).build(); 831 Work work1 = new Work.Builder(TestWorker.class).withInitialState(BLOCKED).build(); 832 insertWorkSpecAndTags(work0); 833 insertWorkSpecAndTags(work1); 834 835 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 836 837 DependencyDao dependencyDao = mDatabase.dependencyDao(); 838 dependencyDao.insertDependency(dependency10); 839 840 mWorkManagerImpl.cancelWorkById(work0.getId()); 841 842 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 843 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 844 } 845 846 @Test 847 @SmallTest 848 public void testCancelWorkForId_cancelsUnfinishedWorkOnly() { 849 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 850 851 Work work0 = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 852 Work work1 = new Work.Builder(TestWorker.class).withInitialState(ENQUEUED).build(); 853 insertWorkSpecAndTags(work0); 854 insertWorkSpecAndTags(work1); 855 856 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 857 858 DependencyDao dependencyDao = mDatabase.dependencyDao(); 859 dependencyDao.insertDependency(dependency10); 860 861 mWorkManagerImpl.cancelWorkById(work0.getId()); 862 863 assertThat(workSpecDao.getState(work0.getId()), is(SUCCEEDED)); 864 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 865 } 866 867 @Test 868 @SmallTest 869 public void testCancelAllWorkWithTag() { 870 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 871 872 final String tagToClear = "tag_to_clear"; 873 final String tagNotToClear = "tag_not_to_clear"; 874 875 Work work0 = new Work.Builder(TestWorker.class).addTag(tagToClear).build(); 876 Work work1 = new Work.Builder(TestWorker.class).addTag(tagToClear).build(); 877 Work work2 = new Work.Builder(TestWorker.class).addTag(tagNotToClear).build(); 878 Work work3 = new Work.Builder(TestWorker.class).addTag(tagNotToClear).build(); 879 insertWorkSpecAndTags(work0); 880 insertWorkSpecAndTags(work1); 881 insertWorkSpecAndTags(work2); 882 insertWorkSpecAndTags(work3); 883 884 mWorkManagerImpl.cancelAllWorkWithTag(tagToClear); 885 886 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 887 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 888 assertThat(workSpecDao.getState(work2.getId()), is(not(CANCELLED))); 889 assertThat(workSpecDao.getState(work3.getId()), is(not(CANCELLED))); 890 } 891 892 @Test 893 @SmallTest 894 public void testCancelAllWorkWithTag_cancelsDependentWork() { 895 String tag = "tag"; 896 897 Work work0 = new Work.Builder(TestWorker.class).addTag(tag).build(); 898 Work work1 = new Work.Builder(TestWorker.class).build(); 899 Work work2 = new Work.Builder(TestWorker.class).build(); 900 Work work3 = new Work.Builder(TestWorker.class).build(); 901 Work work4 = new Work.Builder(TestWorker.class).build(); 902 903 insertWorkSpecAndTags(work0); 904 insertWorkSpecAndTags(work1); 905 insertWorkSpecAndTags(work2); 906 insertWorkSpecAndTags(work3); 907 insertWorkSpecAndTags(work4); 908 909 // Dependency graph: 910 // 0 911 // | 912 // |------------| 913 // 3 1 4 914 // | | 915 // ------------ 916 // | 917 // 2 918 919 Dependency dependency21 = new Dependency(work2.getId(), work1.getId()); 920 Dependency dependency23 = new Dependency(work2.getId(), work3.getId()); 921 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 922 Dependency dependency40 = new Dependency(work4.getId(), work0.getId()); 923 924 DependencyDao dependencyDao = mDatabase.dependencyDao(); 925 dependencyDao.insertDependency(dependency21); 926 dependencyDao.insertDependency(dependency23); 927 dependencyDao.insertDependency(dependency10); 928 dependencyDao.insertDependency(dependency40); 929 930 mWorkManagerImpl.cancelAllWorkWithTag(tag); 931 932 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 933 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 934 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 935 assertThat(workSpecDao.getState(work2.getId()), is(CANCELLED)); 936 assertThat(workSpecDao.getState(work3.getId()), is(not(CANCELLED))); 937 assertThat(workSpecDao.getState(work4.getId()), is(CANCELLED)); 938 } 939 940 @Test 941 @SmallTest 942 public void testSynchronousCancelAndGetStatus() { 943 Work work = new Work.Builder(TestWorker.class).build(); 944 insertWorkSpecAndTags(work); 945 946 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 947 assertThat(workSpecDao.getState(work.getId()), is(ENQUEUED)); 948 949 mWorkManagerImpl.cancelWorkByIdBlocking(work.getId()); 950 assertThat(mWorkManagerImpl.getStatusByIdBlocking(work.getId()).getState(), is(CANCELLED)); 951 } 952 953 @Test 954 @SmallTest 955 public void testGenerateCleanupCallback_resetsRunningWorkStatuses() { 956 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 957 958 Work work = new Work.Builder(TestWorker.class).withInitialState(RUNNING).build(); 959 workSpecDao.insertWorkSpec(getWorkSpec(work)); 960 961 assertThat(workSpecDao.getState(work.getId()), is(RUNNING)); 962 963 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 964 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 965 WorkDatabase.generateCleanupCallback().onOpen(db); 966 967 assertThat(workSpecDao.getState(work.getId()), is(ENQUEUED)); 968 } 969 970 @Test 971 @SmallTest 972 public void testGenerateCleanupCallback_deletesOldFinishedWork() { 973 Work work1 = new Work.Builder(TestWorker.class) 974 .withInitialState(SUCCEEDED) 975 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 976 .build(); 977 Work work2 = new Work.Builder(TestWorker.class) 978 .withPeriodStartTime(Long.MAX_VALUE, TimeUnit.MILLISECONDS) 979 .build(); 980 981 insertWorkSpecAndTags(work1); 982 insertWorkSpecAndTags(work2); 983 984 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 985 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 986 WorkDatabase.generateCleanupCallback().onOpen(db); 987 988 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 989 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(nullValue())); 990 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(not(nullValue()))); 991 } 992 993 @Test 994 @SmallTest 995 public void testGenerateCleanupCallback_doesNotDeleteOldFinishedWorkWithActiveDependents() { 996 Work work0 = new Work.Builder(TestWorker.class) 997 .withInitialState(SUCCEEDED) 998 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 999 .build(); 1000 Work work1 = new Work.Builder(TestWorker.class) 1001 .withInitialState(SUCCEEDED) 1002 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 1003 .build(); 1004 Work work2 = new Work.Builder(TestWorker.class) 1005 .withInitialState(ENQUEUED) 1006 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 1007 .build(); 1008 1009 insertWorkSpecAndTags(work0); 1010 insertWorkSpecAndTags(work1); 1011 insertWorkSpecAndTags(work2); 1012 1013 // Dependency graph: 0 -> 1 -> 2 1014 1015 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 1016 Dependency dependency21 = new Dependency(work2.getId(), work1.getId()); 1017 DependencyDao dependencyDao = mDatabase.dependencyDao(); 1018 dependencyDao.insertDependency(dependency10); 1019 dependencyDao.insertDependency(dependency21); 1020 1021 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 1022 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 1023 WorkDatabase.generateCleanupCallback().onOpen(db); 1024 1025 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 1026 assertThat(workSpecDao.getWorkSpec(work0.getId()), is(nullValue())); 1027 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(not(nullValue()))); 1028 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(not(nullValue()))); 1029 } 1030 1031 private void insertWorkSpecAndTags(Work work) { 1032 mDatabase.workSpecDao().insertWorkSpec(getWorkSpec(work)); 1033 for (String tag : getTags(work)) { 1034 mDatabase.workTagDao().insert(new WorkTag(tag, work.getId())); 1035 } 1036 } 1037} 1038