WorkManagerImplTest.java revision 21e16f32d901aee5e399832703fb935b9be63ae7
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.List; 71import java.util.concurrent.Executors; 72import java.util.concurrent.TimeUnit; 73 74import androidx.work.Arguments; 75import androidx.work.BackoffPolicy; 76import androidx.work.BaseWork; 77import androidx.work.Constraints; 78import androidx.work.ContentUriTriggers; 79import androidx.work.PeriodicWork; 80import androidx.work.TestLifecycleOwner; 81import androidx.work.Work; 82import androidx.work.WorkContinuation; 83import androidx.work.WorkManagerTest; 84import androidx.work.WorkStatus; 85import androidx.work.impl.model.Dependency; 86import androidx.work.impl.model.DependencyDao; 87import androidx.work.impl.model.WorkSpec; 88import androidx.work.impl.model.WorkSpecDao; 89import androidx.work.impl.model.WorkTag; 90import androidx.work.impl.model.WorkTagDao; 91import androidx.work.impl.utils.taskexecutor.InstantTaskExecutorRule; 92import androidx.work.worker.InfiniteTestWorker; 93import androidx.work.worker.TestWorker; 94 95@RunWith(AndroidJUnit4.class) 96public class WorkManagerImplTest extends WorkManagerTest { 97 private WorkDatabase mDatabase; 98 private WorkManagerImpl mWorkManagerImpl; 99 100 @Rule 101 public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule(); 102 103 @Before 104 public void setUp() { 105 ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() { 106 @Override 107 public void executeOnDiskIO(@NonNull Runnable runnable) { 108 runnable.run(); 109 } 110 111 @Override 112 public void postToMainThread(@NonNull Runnable runnable) { 113 runnable.run(); 114 } 115 116 @Override 117 public boolean isMainThread() { 118 return true; 119 } 120 }); 121 122 Context context = InstrumentationRegistry.getTargetContext(); 123 WorkManagerConfiguration configuration = new WorkManagerConfiguration( 124 context, 125 true, 126 Executors.newSingleThreadExecutor()); 127 mWorkManagerImpl = new WorkManagerImpl(context, configuration); 128 mDatabase = mWorkManagerImpl.getWorkDatabase(); 129 } 130 131 @After 132 public void tearDown() { 133 List<String> ids = mDatabase.workSpecDao().getAllWorkSpecIds(); 134 for (String id : ids) { 135 mWorkManagerImpl.cancelWorkById(id); 136 } 137 mDatabase.close(); 138 ArchTaskExecutor.getInstance().setDelegate(null); 139 } 140 141 @Test 142 @SmallTest 143 public void testEnqueue_insertWork() throws InterruptedException { 144 final int workCount = 3; 145 final Work[] workArray = new Work[workCount]; 146 for (int i = 0; i < workCount; ++i) { 147 workArray[i] = new Work.Builder(TestWorker.class).build(); 148 } 149 mWorkManagerImpl.beginWith(workArray[0]).then(workArray[1]).then(workArray[2]).enqueue(); 150 151 for (int i = 0; i < workCount; ++i) { 152 String id = workArray[i].getId(); 153 assertThat(mDatabase.workSpecDao().getWorkSpec(id), is(notNullValue())); 154 assertThat( 155 "index " + i + " does not have expected number of dependencies!", 156 mDatabase.dependencyDao().getPrerequisites(id).size() > 0, 157 is(i > 0)); 158 } 159 } 160 161 @Test 162 @SmallTest 163 public void testEnqueue_insertMultipleWork() { 164 Work work1 = new Work.Builder(TestWorker.class).build(); 165 Work work2 = new Work.Builder(TestWorker.class).build(); 166 Work work3 = new Work.Builder(TestWorker.class).build(); 167 168 mWorkManagerImpl.enqueue(work1, work2, work3); 169 170 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 171 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(notNullValue())); 172 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(notNullValue())); 173 assertThat(workSpecDao.getWorkSpec(work3.getId()), is(notNullValue())); 174 } 175 176 @Test 177 @SmallTest 178 public void testEnqueue_insertWithDependencies() { 179 Work work1a = new Work.Builder(TestWorker.class).build(); 180 Work work1b = new Work.Builder(TestWorker.class).build(); 181 Work work2 = new Work.Builder(TestWorker.class).build(); 182 Work work3a = new Work.Builder(TestWorker.class).build(); 183 Work work3b = new Work.Builder(TestWorker.class).build(); 184 185 mWorkManagerImpl.beginWith(work1a, work1b).then(work2).then(work3a, work3b).enqueue(); 186 187 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 188 assertThat(workSpecDao.getWorkSpec(work1a.getId()), is(notNullValue())); 189 assertThat(workSpecDao.getWorkSpec(work1b.getId()), is(notNullValue())); 190 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(notNullValue())); 191 assertThat(workSpecDao.getWorkSpec(work3a.getId()), is(notNullValue())); 192 assertThat(workSpecDao.getWorkSpec(work3b.getId()), is(notNullValue())); 193 194 DependencyDao dependencyDao = mDatabase.dependencyDao(); 195 assertThat(dependencyDao.getPrerequisites(work1a.getId()), 196 is(emptyCollectionOf(String.class))); 197 assertThat(dependencyDao.getPrerequisites(work1b.getId()), 198 is(emptyCollectionOf(String.class))); 199 200 List<String> prerequisites = dependencyDao.getPrerequisites(work2.getId()); 201 assertThat(prerequisites, containsInAnyOrder(work1a.getId(), work1b.getId())); 202 203 prerequisites = dependencyDao.getPrerequisites(work3a.getId()); 204 assertThat(prerequisites, containsInAnyOrder(work2.getId())); 205 206 prerequisites = dependencyDao.getPrerequisites(work3b.getId()); 207 assertThat(prerequisites, containsInAnyOrder(work2.getId())); 208 } 209 210 @Test 211 @SmallTest 212 public void testEnqueue_insertWithCompletedDependencies_isNotStatusBlocked() { 213 Work work1 = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 214 215 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 216 workContinuation.enqueue(); 217 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 218 assertThat(workSpecDao.getState(work1.getId()), is(SUCCEEDED)); 219 220 Work work2 = new Work.Builder(InfiniteTestWorker.class).build(); 221 workContinuation.then(work2).enqueue(); 222 assertThat(workSpecDao.getState(work2.getId()), isOneOf(ENQUEUED, RUNNING)); 223 } 224 225 @Test 226 @SmallTest 227 public void testEnqueue_insertWithFailedDependencies_isStatusFailed() { 228 Work work1 = new Work.Builder(TestWorker.class).withInitialState(FAILED).build(); 229 230 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 231 workContinuation.enqueue(); 232 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 233 assertThat(workSpecDao.getState(work1.getId()), is(FAILED)); 234 235 Work work2 = new Work.Builder(TestWorker.class).build(); 236 workContinuation.then(work2).enqueue(); 237 assertThat(workSpecDao.getState(work2.getId()), is(FAILED)); 238 } 239 240 @Test 241 @SmallTest 242 public void testEnqueue_insertWithCancelledDependencies_isStatusCancelled() { 243 Work work1 = new Work.Builder(TestWorker.class).withInitialState(CANCELLED).build(); 244 245 WorkContinuation workContinuation = mWorkManagerImpl.beginWith(work1); 246 workContinuation.enqueue(); 247 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 248 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 249 250 Work work2 = new Work.Builder(TestWorker.class).build(); 251 workContinuation.then(work2).enqueue(); 252 assertThat(workSpecDao.getState(work2.getId()), is(CANCELLED)); 253 } 254 255 @Test 256 @SmallTest 257 @SdkSuppress(minSdkVersion = 23) 258 public void testEnqueue_insertWorkConstraints() { 259 Uri testUri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 260 Uri testUri2 = MediaStore.Images.Media.INTERNAL_CONTENT_URI; 261 262 Work work0 = new Work.Builder(TestWorker.class) 263 .withConstraints( 264 new Constraints.Builder() 265 .setRequiresCharging(true) 266 .setRequiresDeviceIdle(true) 267 .setRequiredNetworkType(METERED) 268 .setRequiresBatteryNotLow(true) 269 .setRequiresStorageNotLow(true) 270 .addContentUriTrigger(testUri1, true) 271 .addContentUriTrigger(testUri2, false) 272 .build()) 273 .build(); 274 Work work1 = new Work.Builder(TestWorker.class).build(); 275 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 276 277 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 278 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 279 280 ContentUriTriggers expectedTriggers = new ContentUriTriggers(); 281 expectedTriggers.add(testUri1, true); 282 expectedTriggers.add(testUri2, false); 283 284 Constraints constraints = workSpec0.getConstraints(); 285 assertThat(constraints, is(notNullValue())); 286 assertThat(constraints.requiresCharging(), is(true)); 287 assertThat(constraints.requiresDeviceIdle(), is(true)); 288 assertThat(constraints.requiresBatteryNotLow(), is(true)); 289 assertThat(constraints.requiresStorageNotLow(), is(true)); 290 assertThat(constraints.getRequiredNetworkType(), is(METERED)); 291 if (Build.VERSION.SDK_INT >= 24) { 292 assertThat(constraints.getContentUriTriggers(), is(expectedTriggers)); 293 } else { 294 assertThat(constraints.getContentUriTriggers(), is(new ContentUriTriggers())); 295 } 296 297 constraints = workSpec1.getConstraints(); 298 assertThat(constraints, is(notNullValue())); 299 assertThat(constraints.requiresCharging(), is(false)); 300 assertThat(constraints.requiresDeviceIdle(), is(false)); 301 assertThat(constraints.requiresBatteryNotLow(), is(false)); 302 assertThat(constraints.requiresStorageNotLow(), is(false)); 303 assertThat(constraints.getRequiredNetworkType(), is(NOT_REQUIRED)); 304 assertThat(constraints.getContentUriTriggers().size(), is(0)); 305 } 306 307 @Test 308 @SmallTest 309 public void testEnqueue_insertWorkInitialDelay() { 310 final long expectedInitialDelay = 5000L; 311 Work work0 = new Work.Builder(TestWorker.class) 312 .withInitialDelay(expectedInitialDelay, TimeUnit.MILLISECONDS) 313 .build(); 314 Work work1 = new Work.Builder(TestWorker.class).build(); 315 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 316 317 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 318 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 319 320 assertThat(workSpec0.getInitialDelay(), is(expectedInitialDelay)); 321 assertThat(workSpec1.getInitialDelay(), is(0L)); 322 } 323 324 @Test 325 @SmallTest 326 public void testEnqueue_insertWorkBackoffPolicy() { 327 Work work0 = new Work.Builder(TestWorker.class) 328 .withBackoffCriteria(BackoffPolicy.LINEAR, 50000, TimeUnit.MILLISECONDS) 329 .build(); 330 Work work1 = new Work.Builder(TestWorker.class).build(); 331 mWorkManagerImpl.beginWith(work0).then(work1).enqueue(); 332 333 WorkSpec workSpec0 = mDatabase.workSpecDao().getWorkSpec(work0.getId()); 334 WorkSpec workSpec1 = mDatabase.workSpecDao().getWorkSpec(work1.getId()); 335 336 assertThat(workSpec0.getBackoffPolicy(), is(BackoffPolicy.LINEAR)); 337 assertThat(workSpec0.getBackoffDelayDuration(), is(50000L)); 338 339 assertThat(workSpec1.getBackoffPolicy(), is(BackoffPolicy.EXPONENTIAL)); 340 assertThat(workSpec1.getBackoffDelayDuration(), is(BaseWork.DEFAULT_BACKOFF_DELAY_MILLIS)); 341 } 342 343 @Test 344 @SmallTest 345 public void testEnqueue_insertWorkTags() { 346 final String firstTag = "first_tag"; 347 final String secondTag = "second_tag"; 348 final String thirdTag = "third_tag"; 349 350 Work work0 = new Work.Builder(TestWorker.class).addTag(firstTag).addTag(secondTag).build(); 351 Work work1 = new Work.Builder(TestWorker.class).addTag(firstTag).build(); 352 Work work2 = new Work.Builder(TestWorker.class).build(); 353 mWorkManagerImpl.beginWith(work0).then(work1).then(work2).enqueue(); 354 355 WorkTagDao workTagDao = mDatabase.workTagDao(); 356 assertThat(workTagDao.getWorkSpecsWithTag(firstTag), 357 containsInAnyOrder(work0.getId(), work1.getId())); 358 assertThat(workTagDao.getWorkSpecsWithTag(secondTag), containsInAnyOrder(work0.getId())); 359 assertThat(workTagDao.getWorkSpecsWithTag(thirdTag), emptyCollectionOf(String.class)); 360 } 361 362 @Test 363 @SmallTest 364 public void testEnqueue_insertPeriodicWork() { 365 PeriodicWork periodicWork = new PeriodicWork.Builder( 366 TestWorker.class, 367 PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS, 368 TimeUnit.MILLISECONDS) 369 .build(); 370 mWorkManagerImpl.enqueue(periodicWork); 371 372 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getId()); 373 assertThat(workSpec.isPeriodic(), is(true)); 374 assertThat(workSpec.getIntervalDuration(), is(PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS)); 375 assertThat(workSpec.getFlexDuration(), is(PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS)); 376 } 377 378 @Test 379 @SmallTest 380 public void testEnqueued_work_setsPeriodStartTime() { 381 Work work = new Work.Builder(TestWorker.class).build(); 382 assertThat(getWorkSpec(work).getPeriodStartTime(), is(0L)); 383 384 long beforeEnqueueTime = System.currentTimeMillis(); 385 386 mWorkManagerImpl.enqueue(work); 387 388 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getId()); 389 assertThat(workSpec.getPeriodStartTime(), is(greaterThanOrEqualTo(beforeEnqueueTime))); 390 } 391 392 @Test 393 @SmallTest 394 public void testEnqueued_periodicWork_setsPeriodStartTime() { 395 PeriodicWork periodicWork = new PeriodicWork.Builder( 396 TestWorker.class, 397 PeriodicWork.MIN_PERIODIC_INTERVAL_MILLIS, 398 TimeUnit.MILLISECONDS) 399 .build(); 400 assertThat(getWorkSpec(periodicWork).getPeriodStartTime(), is(0L)); 401 402 long beforeEnqueueTime = System.currentTimeMillis(); 403 404 mWorkManagerImpl.enqueue(periodicWork); 405 406 WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(periodicWork.getId()); 407 assertThat(workSpec.getPeriodStartTime(), is(greaterThanOrEqualTo(beforeEnqueueTime))); 408 } 409 410 @Test 411 @SmallTest 412 public void testUniqueTagSequence_setsUniqueTag() { 413 final String testTag = "mytag"; 414 415 Work work = new Work.Builder(TestWorker.class).build(); 416 mWorkManagerImpl.beginWithUniqueTag(testTag, REPLACE) 417 .then(work) 418 .enqueue(); 419 420 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 421 assertThat(work.getId(), isIn(workSpecIds)); 422 } 423 424 @Test 425 @SmallTest 426 public void testUniqueTagSequence_deletesOldTagsOnReplace() { 427 final String testTag = "mytag"; 428 429 Work originalWork = new Work.Builder(TestWorker.class).addTag(testTag).build(); 430 insertWorkSpecAndTags(originalWork); 431 432 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 433 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 434 mWorkManagerImpl 435 .beginWithUniqueTag(testTag, REPLACE, replacementWork1) 436 .then(replacementWork2) 437 .enqueue(); 438 439 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 440 assertThat( 441 workSpecIds, 442 containsInAnyOrder(replacementWork1.getId(), replacementWork2.getId())); 443 444 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 445 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(nullValue())); 446 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(not(nullValue()))); 447 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(not(nullValue()))); 448 } 449 450 @Test 451 @SmallTest 452 public void testUniqueTagSequence_keepsExistingWorkOnKeep() { 453 final String testTag = "mytag"; 454 455 Work originalWork = new Work.Builder(TestWorker.class).addTag(testTag).build(); 456 insertWorkSpecAndTags(originalWork); 457 458 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 459 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 460 mWorkManagerImpl 461 .beginWithUniqueTag(testTag, KEEP, replacementWork1) 462 .then(replacementWork2) 463 .enqueue(); 464 465 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 466 assertThat(workSpecIds, containsInAnyOrder(originalWork.getId())); 467 468 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 469 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(not(nullValue()))); 470 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(nullValue())); 471 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(nullValue())); 472 } 473 474 @Test 475 @SmallTest 476 public void testUniqueTagSequence_replacesExistingWorkOnKeepWhenExistingWorkIsFinished() { 477 final String testTag = "mytag"; 478 479 Work originalWork = new Work.Builder(TestWorker.class) 480 .withInitialState(SUCCEEDED) 481 .addTag(testTag) 482 .build(); 483 insertWorkSpecAndTags(originalWork); 484 485 Work replacementWork1 = new Work.Builder(TestWorker.class).build(); 486 Work replacementWork2 = new Work.Builder(TestWorker.class).build(); 487 mWorkManagerImpl 488 .beginWithUniqueTag(testTag, KEEP, replacementWork1) 489 .then(replacementWork2) 490 .enqueue(); 491 492 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 493 assertThat(workSpecIds, 494 containsInAnyOrder(replacementWork1.getId(), replacementWork2.getId())); 495 496 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 497 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(nullValue())); 498 assertThat(workSpecDao.getWorkSpec(replacementWork1.getId()), is(not(nullValue()))); 499 assertThat(workSpecDao.getWorkSpec(replacementWork2.getId()), is(not(nullValue()))); 500 } 501 502 @Test 503 @SmallTest 504 public void testUniqueTagSequence_appendsExistingWorkOnAppend() { 505 final String testTag = "mytag"; 506 507 Work originalWork = new Work.Builder(TestWorker.class).addTag(testTag).build(); 508 insertWorkSpecAndTags(originalWork); 509 510 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 511 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 512 mWorkManagerImpl 513 .beginWithUniqueTag(testTag, APPEND, appendWork1) 514 .then(appendWork2) 515 .enqueue(); 516 517 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 518 assertThat(workSpecIds, 519 containsInAnyOrder(originalWork.getId(), appendWork1.getId(), appendWork2.getId())); 520 521 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 522 assertThat(workSpecDao.getWorkSpec(originalWork.getId()), is(not(nullValue()))); 523 assertThat(workSpecDao.getState(appendWork1.getId()), is(BLOCKED)); 524 assertThat(workSpecDao.getState(appendWork2.getId()), is(BLOCKED)); 525 526 assertThat(mDatabase.dependencyDao().getDependentWorkIds(originalWork.getId()), 527 containsInAnyOrder(appendWork1.getId())); 528 } 529 530 @Test 531 @SmallTest 532 public void testUniqueTagSequence_appendsExistingWorkToOnlyLeavesOnAppend() { 533 final String testTag = "mytag"; 534 535 Work originalWork1 = new Work.Builder(TestWorker.class).addTag(testTag).build(); 536 Work originalWork2 = new Work.Builder(TestWorker.class).addTag(testTag).build(); 537 Work originalWork3 = new Work.Builder(TestWorker.class).addTag(testTag).build(); 538 Work originalWork4 = new Work.Builder(TestWorker.class).addTag(testTag).build(); 539 insertWorkSpecAndTags(originalWork1); 540 insertWorkSpecAndTags(originalWork2); 541 insertWorkSpecAndTags(originalWork3); 542 insertWorkSpecAndTags(originalWork4); 543 544 Dependency dependency21 = new Dependency(originalWork2.getId(), originalWork1.getId()); 545 Dependency dependency32 = new Dependency(originalWork3.getId(), originalWork2.getId()); 546 Dependency dependency42 = new Dependency(originalWork4.getId(), originalWork2.getId()); 547 548 DependencyDao dependencyDao = mDatabase.dependencyDao(); 549 dependencyDao.insertDependency(dependency21); 550 dependencyDao.insertDependency(dependency32); 551 dependencyDao.insertDependency(dependency42); 552 553 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 554 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 555 mWorkManagerImpl 556 .beginWithUniqueTag(testTag, APPEND, appendWork1) 557 .then(appendWork2) 558 .enqueue(); 559 560 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 561 assertThat(workSpecIds, 562 containsInAnyOrder( 563 originalWork1.getId(), 564 originalWork2.getId(), 565 originalWork3.getId(), 566 originalWork4.getId(), 567 appendWork1.getId(), 568 appendWork2.getId())); 569 570 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 571 assertThat(workSpecDao.getWorkSpec(originalWork1.getId()), is(not(nullValue()))); 572 assertThat(workSpecDao.getWorkSpec(originalWork2.getId()), is(not(nullValue()))); 573 assertThat(workSpecDao.getWorkSpec(originalWork3.getId()), is(not(nullValue()))); 574 assertThat(workSpecDao.getWorkSpec(originalWork4.getId()), is(not(nullValue()))); 575 assertThat(workSpecDao.getState(appendWork1.getId()), is(BLOCKED)); 576 assertThat(workSpecDao.getState(appendWork2.getId()), is(BLOCKED)); 577 578 assertThat(dependencyDao.getPrerequisites(appendWork1.getId()), 579 containsInAnyOrder(originalWork3.getId(), originalWork4.getId())); 580 assertThat(dependencyDao.getPrerequisites(appendWork2.getId()), 581 containsInAnyOrder(appendWork1.getId())); 582 } 583 584 @Test 585 @SmallTest 586 public void testUniqueTagSequence_insertsExistingWorkWhenNothingToAppendTo() { 587 final String testTag = "mytag"; 588 589 Work appendWork1 = new Work.Builder(TestWorker.class).build(); 590 Work appendWork2 = new Work.Builder(TestWorker.class).build(); 591 mWorkManagerImpl 592 .beginWithUniqueTag(testTag, APPEND, appendWork1) 593 .then(appendWork2) 594 .enqueue(); 595 596 List<String> workSpecIds = mDatabase.workTagDao().getWorkSpecsWithTag(testTag); 597 assertThat(workSpecIds, 598 containsInAnyOrder(appendWork1.getId(), appendWork2.getId())); 599 } 600 601 @Test 602 @SmallTest 603 public void testGetStatusSync() { 604 Work work = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 605 insertWorkSpecAndTags(work); 606 607 WorkStatus workStatus = mWorkManagerImpl.getStatusSync(work.getId()); 608 assertThat(workStatus.getId(), is(work.getId())); 609 assertThat(workStatus.getState(), is(SUCCEEDED)); 610 } 611 612 @Test 613 @SmallTest 614 public void testGetStatusSync_ReturnsNullIfNotInDatabase() { 615 WorkStatus workStatus = mWorkManagerImpl.getStatusSync("dummy"); 616 assertThat(workStatus, is(nullValue())); 617 } 618 619 @Test 620 @SmallTest 621 @SuppressWarnings("unchecked") 622 public void testGetStatuses() { 623 Work work0 = new Work.Builder(TestWorker.class).build(); 624 Work work1 = new Work.Builder(TestWorker.class).build(); 625 insertWorkSpecAndTags(work0); 626 insertWorkSpecAndTags(work1); 627 628 Observer<List<WorkStatus>> mockObserver = mock(Observer.class); 629 630 TestLifecycleOwner testLifecycleOwner = new TestLifecycleOwner(); 631 LiveData<List<WorkStatus>> liveData = 632 mWorkManagerImpl.getStatuses(Arrays.asList(work0.getId(), work1.getId())); 633 liveData.observe(testLifecycleOwner, mockObserver); 634 635 ArgumentCaptor<List<WorkStatus>> captor = 636 ArgumentCaptor.forClass(List.class); 637 verify(mockObserver).onChanged(captor.capture()); 638 assertThat(captor.getValue(), is(not(nullValue()))); 639 assertThat(captor.getValue().size(), is(2)); 640 641 WorkStatus workStatus0 = new WorkStatus(work0.getId(), ENQUEUED, Arguments.EMPTY); 642 WorkStatus workStatus1 = new WorkStatus(work1.getId(), ENQUEUED, Arguments.EMPTY); 643 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 644 645 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 646 workSpecDao.setState(RUNNING, work0.getId()); 647 648 verify(mockObserver, times(2)).onChanged(captor.capture()); 649 assertThat(captor.getValue(), is(not(nullValue()))); 650 assertThat(captor.getValue().size(), is(2)); 651 652 workStatus0 = new WorkStatus(work0.getId(), RUNNING, Arguments.EMPTY); 653 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 654 655 clearInvocations(mockObserver); 656 workSpecDao.setState(RUNNING, work1.getId()); 657 658 verify(mockObserver).onChanged(captor.capture()); 659 assertThat(captor.getValue(), is(not(nullValue()))); 660 assertThat(captor.getValue().size(), is(2)); 661 662 workStatus1 = new WorkStatus(work1.getId(), RUNNING, Arguments.EMPTY); 663 assertThat(captor.getValue(), containsInAnyOrder(workStatus0, workStatus1)); 664 665 liveData.removeObservers(testLifecycleOwner); 666 } 667 668 @Test 669 @SmallTest 670 public void testCancelWorkForId() { 671 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 672 673 Work work0 = new Work.Builder(TestWorker.class).build(); 674 Work work1 = new Work.Builder(TestWorker.class).build(); 675 insertWorkSpecAndTags(work0); 676 insertWorkSpecAndTags(work1); 677 678 mWorkManagerImpl.cancelWorkById(work0.getId()); 679 680 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 681 assertThat(workSpecDao.getState(work1.getId()), is(not(CANCELLED))); 682 } 683 684 @Test 685 @SmallTest 686 public void testCancelWorkForId_cancelsDependentWork() { 687 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 688 689 Work work0 = new Work.Builder(TestWorker.class).build(); 690 Work work1 = new Work.Builder(TestWorker.class).withInitialState(BLOCKED).build(); 691 insertWorkSpecAndTags(work0); 692 insertWorkSpecAndTags(work1); 693 694 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 695 696 DependencyDao dependencyDao = mDatabase.dependencyDao(); 697 dependencyDao.insertDependency(dependency10); 698 699 mWorkManagerImpl.cancelWorkById(work0.getId()); 700 701 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 702 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 703 } 704 705 @Test 706 @SmallTest 707 public void testCancelWorkForId_cancelsUnfinishedWorkOnly() { 708 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 709 710 Work work0 = new Work.Builder(TestWorker.class).withInitialState(SUCCEEDED).build(); 711 Work work1 = new Work.Builder(TestWorker.class).withInitialState(ENQUEUED).build(); 712 insertWorkSpecAndTags(work0); 713 insertWorkSpecAndTags(work1); 714 715 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 716 717 DependencyDao dependencyDao = mDatabase.dependencyDao(); 718 dependencyDao.insertDependency(dependency10); 719 720 mWorkManagerImpl.cancelWorkById(work0.getId()); 721 722 assertThat(workSpecDao.getState(work0.getId()), is(SUCCEEDED)); 723 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 724 } 725 726 @Test 727 @SmallTest 728 public void testCancelAllWorkWithTag() { 729 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 730 731 final String tagToClear = "tag_to_clear"; 732 final String tagNotToClear = "tag_not_to_clear"; 733 734 Work work0 = new Work.Builder(TestWorker.class).addTag(tagToClear).build(); 735 Work work1 = new Work.Builder(TestWorker.class).addTag(tagToClear).build(); 736 Work work2 = new Work.Builder(TestWorker.class).addTag(tagNotToClear).build(); 737 Work work3 = new Work.Builder(TestWorker.class).addTag(tagNotToClear).build(); 738 insertWorkSpecAndTags(work0); 739 insertWorkSpecAndTags(work1); 740 insertWorkSpecAndTags(work2); 741 insertWorkSpecAndTags(work3); 742 743 mWorkManagerImpl.cancelAllWorkWithTag(tagToClear); 744 745 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 746 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 747 assertThat(workSpecDao.getState(work2.getId()), is(not(CANCELLED))); 748 assertThat(workSpecDao.getState(work3.getId()), is(not(CANCELLED))); 749 } 750 751 @Test 752 @SmallTest 753 public void testCancelAllWorkWithTag_cancelsDependentWork() { 754 String tag = "tag"; 755 756 Work work0 = new Work.Builder(TestWorker.class).addTag(tag).build(); 757 Work work1 = new Work.Builder(TestWorker.class).build(); 758 Work work2 = new Work.Builder(TestWorker.class).build(); 759 Work work3 = new Work.Builder(TestWorker.class).build(); 760 Work work4 = new Work.Builder(TestWorker.class).build(); 761 762 insertWorkSpecAndTags(work0); 763 insertWorkSpecAndTags(work1); 764 insertWorkSpecAndTags(work2); 765 insertWorkSpecAndTags(work3); 766 insertWorkSpecAndTags(work4); 767 768 // Dependency graph: 769 // 0 770 // | 771 // |------------| 772 // 3 1 4 773 // | | 774 // ------------ 775 // | 776 // 2 777 778 Dependency dependency21 = new Dependency(work2.getId(), work1.getId()); 779 Dependency dependency23 = new Dependency(work2.getId(), work3.getId()); 780 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 781 Dependency dependency40 = new Dependency(work4.getId(), work0.getId()); 782 783 DependencyDao dependencyDao = mDatabase.dependencyDao(); 784 dependencyDao.insertDependency(dependency21); 785 dependencyDao.insertDependency(dependency23); 786 dependencyDao.insertDependency(dependency10); 787 dependencyDao.insertDependency(dependency40); 788 789 mWorkManagerImpl.cancelAllWorkWithTag(tag); 790 791 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 792 assertThat(workSpecDao.getState(work0.getId()), is(CANCELLED)); 793 assertThat(workSpecDao.getState(work1.getId()), is(CANCELLED)); 794 assertThat(workSpecDao.getState(work2.getId()), is(CANCELLED)); 795 assertThat(workSpecDao.getState(work3.getId()), is(not(CANCELLED))); 796 assertThat(workSpecDao.getState(work4.getId()), is(CANCELLED)); 797 } 798 799 @Test 800 @SmallTest 801 public void testSynchronousCancelAndGetStatus() { 802 Work work = new Work.Builder(TestWorker.class).build(); 803 insertWorkSpecAndTags(work); 804 805 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 806 assertThat(workSpecDao.getState(work.getId()), is(ENQUEUED)); 807 808 mWorkManagerImpl.cancelWorkByIdSync(work.getId()); 809 assertThat(mWorkManagerImpl.getStatusSync(work.getId()).getState(), is(CANCELLED)); 810 } 811 812 @Test 813 @SmallTest 814 public void testGenerateCleanupCallback_resetsRunningWorkStatuses() { 815 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 816 817 Work work = new Work.Builder(TestWorker.class).withInitialState(RUNNING).build(); 818 workSpecDao.insertWorkSpec(getWorkSpec(work)); 819 820 assertThat(workSpecDao.getState(work.getId()), is(RUNNING)); 821 822 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 823 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 824 WorkDatabase.generateCleanupCallback().onOpen(db); 825 826 assertThat(workSpecDao.getState(work.getId()), is(ENQUEUED)); 827 } 828 829 @Test 830 @SmallTest 831 public void testGenerateCleanupCallback_deletesOldFinishedWork() { 832 Work work1 = new Work.Builder(TestWorker.class) 833 .withInitialState(SUCCEEDED) 834 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 835 .build(); 836 Work work2 = new Work.Builder(TestWorker.class) 837 .withPeriodStartTime(Long.MAX_VALUE, TimeUnit.MILLISECONDS) 838 .build(); 839 840 insertWorkSpecAndTags(work1); 841 insertWorkSpecAndTags(work2); 842 843 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 844 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 845 WorkDatabase.generateCleanupCallback().onOpen(db); 846 847 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 848 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(nullValue())); 849 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(not(nullValue()))); 850 } 851 852 @Test 853 @SmallTest 854 public void testGenerateCleanupCallback_doesNotDeleteOldFinishedWorkWithActiveDependents() { 855 Work work0 = new Work.Builder(TestWorker.class) 856 .withInitialState(SUCCEEDED) 857 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 858 .build(); 859 Work work1 = new Work.Builder(TestWorker.class) 860 .withInitialState(SUCCEEDED) 861 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 862 .build(); 863 Work work2 = new Work.Builder(TestWorker.class) 864 .withInitialState(ENQUEUED) 865 .withPeriodStartTime(WorkDatabase.getPruneDate() - 1L, TimeUnit.MILLISECONDS) 866 .build(); 867 868 insertWorkSpecAndTags(work0); 869 insertWorkSpecAndTags(work1); 870 insertWorkSpecAndTags(work2); 871 872 // Dependency graph: 0 -> 1 -> 2 873 874 Dependency dependency10 = new Dependency(work1.getId(), work0.getId()); 875 Dependency dependency21 = new Dependency(work2.getId(), work1.getId()); 876 DependencyDao dependencyDao = mDatabase.dependencyDao(); 877 dependencyDao.insertDependency(dependency10); 878 dependencyDao.insertDependency(dependency21); 879 880 SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper(); 881 SupportSQLiteDatabase db = openHelper.getWritableDatabase(); 882 WorkDatabase.generateCleanupCallback().onOpen(db); 883 884 WorkSpecDao workSpecDao = mDatabase.workSpecDao(); 885 assertThat(workSpecDao.getWorkSpec(work0.getId()), is(nullValue())); 886 assertThat(workSpecDao.getWorkSpec(work1.getId()), is(not(nullValue()))); 887 assertThat(workSpecDao.getWorkSpec(work2.getId()), is(not(nullValue()))); 888 } 889 890 private void insertWorkSpecAndTags(Work work) { 891 mDatabase.workSpecDao().insertWorkSpec(getWorkSpec(work)); 892 for (String tag : getTags(work)) { 893 mDatabase.workTagDao().insert(new WorkTag(tag, work.getId())); 894 } 895 } 896} 897