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