1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.concurrent; 27 28 import com.sun.org.apache.xerces.internal.util.DOMUtil; 29 import javafx.beans.value.ChangeListener; 30 import javafx.beans.value.ObservableValue; 31 import test.javafx.concurrent.mocks.MythicalEvent; 32 import test.javafx.concurrent.mocks.SimpleTask; 33 import javafx.event.Event; 34 import javafx.event.EventHandler; 35 import java.util.concurrent.ConcurrentLinkedQueue; 36 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.Executor; 38 import java.util.concurrent.atomic.AtomicBoolean; 39 import java.util.concurrent.atomic.AtomicInteger; 40 import java.util.concurrent.atomic.AtomicReference; 41 import javafx.concurrent.Service; 42 import javafx.concurrent.ServiceShim; 43 import javafx.concurrent.Task; 44 import javafx.concurrent.TaskShim; 45 import javafx.concurrent.Worker; 46 import javafx.concurrent.WorkerStateEvent; 47 import javafx.event.EventType; 48 import org.junit.After; 49 import org.junit.Test; 50 import static org.junit.Assert.assertEquals; 51 import static org.junit.Assert.assertFalse; 52 import static org.junit.Assert.assertNotNull; 53 import static org.junit.Assert.assertNull; 54 import static org.junit.Assert.assertSame; 55 import static org.junit.Assert.assertTrue; 56 57 /** 58 * Tests various rules regarding the lifecycle of a Service. 59 */ 60 public class ServiceLifecycleTest extends ServiceTestBase { 61 /** 62 * The ManualExecutor is used so that there is some time period between 63 * when something is scheduled and when it actually runs, such that the 64 * test code has to manually tell it that it can now run. 65 */ 66 protected ManualExecutor executor; 67 68 /** 69 * The task to run, which has methods on it to allow me to manually 70 * put it into a passing, failed, or whatnot state. 71 */ 72 protected ManualTask task; 73 74 @Override protected TestServiceFactory setupServiceFactory() { 75 return new TestServiceFactory() { 76 @Override public AbstractTask createTestTask() { 77 return task = new ManualTask(); 78 } 79 }; 80 } 81 82 @Override protected Executor createExecutor() { 83 return executor = new ManualExecutor(super.createExecutor()); 84 } 85 86 @After public void tearDown() { 87 if (task != null) task.finish.set(true); 88 } 89 90 /** 91 * This class will schedule the task, and then you can execute 92 * it manually by calling executeScheduled. In this way I can 93 * test when a Service is scheduled but not yet started. 94 */ 95 protected final class ManualExecutor implements Executor { 96 private Runnable scheduled; 97 private Executor wrapped; 98 99 ManualExecutor(Executor wrapped) { 100 this.wrapped = wrapped; 101 } 102 103 @Override public void execute(Runnable command) { 104 this.scheduled = command; 105 } 106 107 public void executeScheduled() { 108 wrapped.execute(scheduled); 109 // I need to wait until the next "Sentinel" runnable 110 // on the queue, which the Task will post when it begins 111 // execution. 112 handleEvents(); 113 } 114 } 115 116 protected final class ManualTask extends AbstractTask { 117 private AtomicBoolean finish = new AtomicBoolean(false); 118 private AtomicReference<Exception> exception = new AtomicReference<>(); 119 private boolean failToCancel = false; 120 121 @Override protected String call() throws Exception { 122 runLater(new Sentinel()); 123 while (!finish.get()) { 124 Exception e = exception.get(); 125 if (e != null) throw e; 126 } 127 return "Done"; 128 } 129 130 public void progress(long done, long max) { 131 updateProgress(done, max); 132 } 133 134 public void message(String msg) { 135 updateMessage(msg); 136 } 137 138 public void title(String t) { 139 updateTitle(t); 140 } 141 142 public void fail(Exception e) { 143 exception.set(e); 144 handleEvents(); 145 } 146 147 public void complete() { 148 finish.set(true); 149 handleEvents(); 150 } 151 152 @Override 153 public boolean cancel(boolean mayInterruptIfRunning) { 154 boolean result = failToCancel ? false : super.cancel(mayInterruptIfRunning); 155 finish.set(true); 156 return result; 157 } 158 } 159 160 /************************************************************************ 161 * Tests while in the ready state * 162 ***********************************************************************/ 163 164 @Test public void callingStartInReadyStateSchedulesJob() { 165 assertNull(executor.scheduled); 166 service.start(); 167 assertNotNull(executor.scheduled); 168 } 169 170 @Test public void callingStartInReadyMovesToScheduledState() { 171 service.start(); 172 assertSame(Worker.State.SCHEDULED, service.getState()); 173 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 174 } 175 176 @Test public void callingRestartInReadyStateSchedulesJob() { 177 assertNull(executor.scheduled); 178 service.restart(); 179 assertNotNull(executor.scheduled); 180 } 181 182 @Test public void callingRestartInReadyMovesToScheduledState() { 183 service.restart(); 184 assertSame(Worker.State.SCHEDULED, service.getState()); 185 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 186 } 187 188 @Test public void callingCancelInReadyStateMovesToCancelledState() { 189 service.cancel(); 190 assertSame(Worker.State.CANCELLED, service.getState()); 191 assertSame(Worker.State.CANCELLED, service.stateProperty().get()); 192 } 193 194 @Test public void callingResetInReadyStateHasNoEffect() { 195 service.reset(); 196 assertSame(Worker.State.READY, service.getState()); 197 assertSame(Worker.State.READY, service.stateProperty().get()); 198 } 199 200 /************************************************************************ 201 * Tests while in the scheduled state * 202 ***********************************************************************/ 203 204 @Test(expected = IllegalStateException.class) 205 public void callingStartInScheduledStateIsISE() { 206 service.start(); 207 service.start(); 208 } 209 210 @Test public void callingCancelInScheduledStateResultsInCancelledState() { 211 service.start(); 212 service.cancel(); 213 assertSame(Worker.State.CANCELLED, service.getState()); 214 assertSame(Worker.State.CANCELLED, service.stateProperty().get()); 215 } 216 217 @Test public void callingRestartInScheduledStateShouldCancelAndReschedule() { 218 service.start(); 219 service.restart(); 220 assertSame(Worker.State.SCHEDULED, service.getState()); 221 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 222 } 223 224 /** 225 * This test differs from callingRestartInScheduledStateShouldCancelAndReschedule 226 * in that under some circumstances, the cancel operation on a task may yield 227 * a task which is not marked as CANCELLED, such as when it is already run 228 * or cancelled). In such a case, the bindings have not fired yet and the 229 * state of the service is off. At least, that is what is happening with 230 * RT-20880. The fix allows this test to pass. 231 */ 232 @Test public void callingRestartInScheduledStateShouldCancelAndReschedule_RT_20880() { 233 service.start(); 234 task.failToCancel = true; 235 service.restart(); 236 assertSame(Worker.State.SCHEDULED, service.getState()); 237 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 238 } 239 240 @Test(expected = IllegalStateException.class) 241 public void callingResetInScheduledStateThrowsISE() { 242 service.start(); 243 service.reset(); 244 } 245 246 @Test public void stateChangesToRunningWhenExecutorExecutes() { 247 service.start(); 248 executor.executeScheduled(); 249 assertSame(Worker.State.RUNNING, service.getState()); 250 assertSame(Worker.State.RUNNING, service.stateProperty().get()); 251 } 252 253 @Test public void exceptionShouldBeNullInScheduledState() { 254 service.start(); 255 assertNull(service.getException()); 256 assertNull(service.exceptionProperty().get()); 257 } 258 259 @Test public void valueShouldBeNullInScheduledState() { 260 service.start(); 261 assertNull(service.getValue()); 262 assertNull(service.valueProperty().get()); 263 } 264 265 @Test public void runningShouldBeTrueInScheduledState() { 266 service.start(); 267 assertTrue(service.isRunning()); 268 assertTrue(service.runningProperty().get()); 269 } 270 271 @Test public void runningPropertyNotificationInScheduledState() { 272 final AtomicBoolean passed = new AtomicBoolean(false); 273 service.runningProperty().addListener((o, oldValue, newValue) -> passed.set(newValue)); 274 service.start(); 275 assertTrue(passed.get()); 276 } 277 278 @Test public void workDoneShouldBeNegativeOneInitiallyInScheduledState() { 279 service.start(); 280 assertEquals(-1, service.getWorkDone(), 0); 281 assertEquals(-1, service.workDoneProperty().get(), 0); 282 } 283 284 @Test public void totalWorkShouldBeNegativeOneAtStartOfScheduledState() { 285 service.start(); 286 assertEquals(-1, service.getTotalWork(), 0); 287 assertEquals(-1, service.totalWorkProperty().get(), 0); 288 } 289 290 @Test public void progressShouldBeNegativeOneAtStartOfScheduledState() { 291 service.start(); 292 assertEquals(-1, service.getProgress(), 0); 293 assertEquals(-1, task.progressProperty().get(), 0); 294 } 295 296 @Test public void messageShouldBeEmptyStringWhenEnteringScheduledState() { 297 service.start(); 298 assertEquals("", service.getMessage()); 299 assertEquals("", task.messageProperty().get()); 300 } 301 302 @Test public void titleShouldBeEmptyStringAtStartOfScheduledState() { 303 service.start(); 304 assertEquals("", service.getTitle()); 305 assertEquals("", task.titleProperty().get()); 306 } 307 308 /************************************************************************ 309 * Tests while in the running state * 310 ***********************************************************************/ 311 312 @Test(expected = IllegalStateException.class) 313 public void callingStartInRunningStateIsISE() { 314 service.start(); 315 executor.executeScheduled(); 316 service.start(); 317 } 318 319 @Test(expected = IllegalStateException.class) 320 public void callingResetInRunningStateIsISE() { 321 service.start(); 322 executor.executeScheduled(); 323 service.reset(); 324 } 325 326 @Test public void callingRestartInRunningStateCancelsAndReschedules() { 327 service.start(); 328 executor.executeScheduled(); 329 service.restart(); 330 assertSame(Worker.State.SCHEDULED, service.getState()); 331 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 332 } 333 334 @Test public void callingCancelInRunningStateResultsInCancelledState() { 335 service.start(); 336 executor.executeScheduled(); 337 service.cancel(); 338 assertSame(Worker.State.CANCELLED, service.getState()); 339 assertSame(Worker.State.CANCELLED, service.stateProperty().get()); 340 } 341 342 @Test public void exceptionShouldBeNullInRunningState() { 343 service.start(); 344 executor.executeScheduled(); 345 assertNull(service.getException()); 346 assertNull(service.exceptionProperty().get()); 347 } 348 349 @Test public void valueShouldBeNullInRunningState() { 350 service.start(); 351 executor.executeScheduled(); 352 assertNull(service.getValue()); 353 assertNull(service.valueProperty().get()); 354 } 355 356 @Test public void runningShouldBeTrueInRunningState() { 357 service.start(); 358 executor.executeScheduled(); 359 assertTrue(service.isRunning()); 360 assertTrue(service.runningProperty().get()); 361 } 362 363 @Test public void runningPropertyNotificationInRunningState() { 364 final AtomicBoolean passed = new AtomicBoolean(false); 365 service.runningProperty().addListener((o, oldValue, newValue) -> passed.set(newValue)); 366 service.start(); 367 executor.executeScheduled(); 368 assertTrue(passed.get()); 369 } 370 371 @Test public void workDoneShouldBeNegativeOneInitiallyInRunningState() { 372 service.start(); 373 executor.executeScheduled(); 374 assertEquals(-1, service.getWorkDone(), 0); 375 assertEquals(-1, service.workDoneProperty().get(), 0); 376 } 377 378 @Test public void workDoneShouldAdvanceTo10() { 379 service.start(); 380 executor.executeScheduled(); 381 task.progress(10, 20); 382 assertEquals(10, service.getWorkDone(), 0); 383 assertEquals(10, service.workDoneProperty().get(), 0); 384 } 385 386 @Test public void workDonePropertyNotification() { 387 final AtomicBoolean passed = new AtomicBoolean(false); 388 service.workDoneProperty().addListener((o, oldValue, newValue) -> passed.set(newValue.doubleValue() == 10)); 389 service.start(); 390 executor.executeScheduled(); 391 task.progress(10, 20); 392 assertTrue(passed.get()); 393 } 394 395 @Test public void totalWorkShouldBeNegativeOneAtStartOfRunning() { 396 service.start(); 397 executor.executeScheduled(); 398 assertEquals(-1, service.getTotalWork(), 0); 399 assertEquals(-1, service.totalWorkProperty().get(), 0); 400 } 401 402 @Test public void totalWorkShouldBeTwenty() { 403 service.start(); 404 executor.executeScheduled(); 405 task.progress(10, 20); 406 assertEquals(20, service.getTotalWork(), 0); 407 assertEquals(20, service.totalWorkProperty().get(), 0); 408 } 409 410 @Test public void totalWorkPropertyNotification() { 411 final AtomicBoolean passed = new AtomicBoolean(false); 412 service.totalWorkProperty().addListener((o, oldValue, newValue) -> passed.set(newValue.doubleValue() == 20)); 413 service.start(); 414 executor.executeScheduled(); 415 task.progress(10, 20); 416 assertTrue(passed.get()); 417 } 418 419 @Test public void progressShouldBeNegativeOneAtStartOfRunningState() { 420 service.start(); 421 executor.executeScheduled(); 422 assertEquals(-1, service.getProgress(), 0); 423 assertEquals(-1, task.progressProperty().get(), 0); 424 } 425 426 @Test public void afterRunningProgressShouldBe_FiftyPercent() { 427 service.start(); 428 executor.executeScheduled(); 429 task.progress(10, 20); 430 assertEquals(.5, service.getProgress(), 0); 431 assertEquals(.5, task.progressProperty().get(), 0); 432 } 433 434 @Test public void progressPropertyNotification() { 435 final AtomicBoolean passed = new AtomicBoolean(false); 436 service.start(); 437 task.progressProperty().addListener((o, oldValue, newValue) -> passed.set(newValue.doubleValue() == .5)); 438 executor.executeScheduled(); 439 task.progress(10, 20); 440 assertTrue(passed.get()); 441 } 442 443 @Test public void messageShouldBeEmptyStringWhenEnteringRunningState() { 444 service.start(); 445 executor.executeScheduled(); 446 assertEquals("", service.getMessage()); 447 assertEquals("", task.messageProperty().get()); 448 } 449 450 @Test public void messageShouldBeLastSetValue() { 451 service.start(); 452 executor.executeScheduled(); 453 task.message("Running"); 454 assertEquals("Running", service.getMessage()); 455 assertEquals("Running", task.messageProperty().get()); 456 } 457 458 @Test public void messagePropertyNotification() { 459 final AtomicBoolean passed = new AtomicBoolean(false); 460 service.start(); 461 task.messageProperty().addListener((o, oldValue, newValue) -> passed.set("Running".equals(service.getMessage()))); 462 executor.executeScheduled(); 463 task.message("Running"); 464 assertTrue(passed.get()); 465 } 466 467 @Test public void titleShouldBeEmptyStringAtStartOfRunningState() { 468 service.start(); 469 executor.executeScheduled(); 470 assertEquals("", service.getTitle()); 471 assertEquals("", task.titleProperty().get()); 472 } 473 474 @Test public void titleShouldBeLastSetValue() { 475 service.start(); 476 executor.executeScheduled(); 477 task.title("Title"); 478 assertEquals("Title", service.getTitle()); 479 assertEquals("Title", task.titleProperty().get()); 480 } 481 482 @Test public void titlePropertyNotification() { 483 final AtomicBoolean passed = new AtomicBoolean(false); 484 service.start(); 485 task.titleProperty().addListener((o, oldValue, newValue) -> passed.set("Title".equals(service.getTitle()))); 486 executor.executeScheduled(); 487 task.title("Title"); 488 assertTrue(passed.get()); 489 } 490 491 /************************************************************************ 492 * Throw an exception in the running state * 493 ***********************************************************************/ 494 495 @Test(expected = IllegalStateException.class) 496 public void callingStartInFailedStateIsISE() { 497 service.start(); 498 executor.executeScheduled(); 499 task.fail(new Exception("anything")); 500 service.start(); 501 } 502 503 @Test public void callingResetInFailedStateResetsStateToREADY() { 504 service.start(); 505 executor.executeScheduled(); 506 task.fail(new Exception("anything")); 507 service.reset(); 508 509 assertSame(Worker.State.READY, service.getState()); 510 assertSame(Worker.State.READY, service.stateProperty().get()); 511 } 512 513 @Test public void callingResetInFailedStateResetsValueToNull() { 514 service.start(); 515 executor.executeScheduled(); 516 task.fail(new Exception("anything")); 517 service.reset(); 518 519 assertNull(service.getValue()); 520 assertNull(service.valueProperty().get()); 521 } 522 523 @Test public void callingResetInFailedStateResetsExceptionToNull() { 524 service.start(); 525 executor.executeScheduled(); 526 task.fail(new Exception("anything")); 527 service.reset(); 528 529 assertNull(service.getException()); 530 assertNull(service.exceptionProperty().get()); 531 } 532 533 @Test public void callingResetInFailedStateResetsWorkDoneToNegativeOne() { 534 service.start(); 535 executor.executeScheduled(); 536 task.progress(10, 20); 537 task.fail(new Exception("anything")); 538 service.reset(); 539 540 assertEquals(-1, service.getWorkDone(), 0); 541 assertEquals(-1, service.workDoneProperty().get(), 0); 542 } 543 544 @Test public void callingResetInFailedStateResetsTotalWorkToNegativeOne() { 545 service.start(); 546 executor.executeScheduled(); 547 task.progress(10, 20); 548 task.fail(new Exception("anything")); 549 service.reset(); 550 551 assertEquals(-1, service.getTotalWork(), 0); 552 assertEquals(-1, service.totalWorkProperty().get(), 0); 553 } 554 555 @Test public void callingResetInFailedStateResetsProgressToNegativeOne() { 556 service.start(); 557 executor.executeScheduled(); 558 task.progress(10, 20); 559 task.fail(new Exception("anything")); 560 service.reset(); 561 562 assertEquals(-1, service.getProgress(), 0); 563 assertEquals(-1, service.progressProperty().get(), 0); 564 } 565 566 @Test public void callingResetInFailedStateResetsRunningToFalse() { 567 service.start(); 568 executor.executeScheduled(); 569 task.fail(new Exception("anything")); 570 service.reset(); 571 572 assertFalse(service.isRunning()); 573 assertFalse(service.runningProperty().get()); 574 } 575 576 @Test public void callingResetInFailedStateResetsMessageToEmptyString() { 577 service.start(); 578 executor.executeScheduled(); 579 task.message("Message"); 580 task.fail(new Exception("anything")); 581 service.reset(); 582 583 assertEquals("", service.getMessage()); 584 assertEquals("", service.messageProperty().get()); 585 } 586 587 @Test public void callingResetInFailedStateResetsTitleToEmptyString() { 588 service.start(); 589 executor.executeScheduled(); 590 task.title("Title"); 591 task.fail(new Exception("anything")); 592 service.reset(); 593 594 assertEquals("", service.getTitle()); 595 assertEquals("", service.titleProperty().get()); 596 } 597 598 @Test public void callingRestartInFailedStateReschedules() { 599 service.start(); 600 executor.executeScheduled(); 601 task.fail(new Exception("anything")); 602 service.restart(); 603 assertSame(Worker.State.SCHEDULED, service.getState()); 604 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 605 } 606 607 @Test public void callingCancelInFailedStateResultsInNoChange() { 608 service.start(); 609 executor.executeScheduled(); 610 task.fail(new Exception("anything")); 611 service.cancel(); 612 assertSame(Worker.State.FAILED, service.getState()); 613 assertSame(Worker.State.FAILED, service.stateProperty().get()); 614 } 615 616 /************************************************************************ 617 * Proper Completion of a task * 618 ***********************************************************************/ 619 620 @Test(expected = IllegalStateException.class) 621 public void callingStartInSucceededStateIsISE() { 622 service.start(); 623 executor.executeScheduled(); 624 task.progress(20, 20); 625 task.complete(); 626 service.start(); 627 } 628 629 @Test public void callingResetInSucceededStateResetsStateToREADY() { 630 service.start(); 631 executor.executeScheduled(); 632 task.progress(20, 20); 633 task.complete(); 634 service.reset(); 635 636 assertSame(Worker.State.READY, service.getState()); 637 assertSame(Worker.State.READY, service.stateProperty().get()); 638 } 639 640 @Test public void callingResetInSucceededStateResetsValueToNull() { 641 service.start(); 642 executor.executeScheduled(); 643 task.progress(20, 20); 644 task.complete(); 645 service.reset(); 646 647 assertNull(service.getValue()); 648 assertNull(service.valueProperty().get()); 649 } 650 651 @Test public void callingResetInSucceededStateResetsExceptionToNull() { 652 service.start(); 653 executor.executeScheduled(); 654 task.progress(20, 20); 655 task.complete(); 656 service.reset(); 657 658 assertNull(service.getException()); 659 assertNull(service.exceptionProperty().get()); 660 } 661 662 @Test public void callingResetInSucceededStateResetsWorkDoneToNegativeOne() { 663 service.start(); 664 executor.executeScheduled(); 665 task.progress(20, 20); 666 task.complete(); 667 service.reset(); 668 669 assertEquals(-1, service.getWorkDone(), 0); 670 assertEquals(-1, service.workDoneProperty().get(), 0); 671 } 672 673 @Test public void callingResetInSucceededStateResetsTotalWorkToNegativeOne() { 674 service.start(); 675 executor.executeScheduled(); 676 task.progress(20, 20); 677 task.complete(); 678 service.reset(); 679 680 assertEquals(-1, service.getTotalWork(), 0); 681 assertEquals(-1, service.totalWorkProperty().get(), 0); 682 } 683 684 @Test public void callingResetInSucceededStateResetsProgressToNegativeOne() { 685 service.start(); 686 executor.executeScheduled(); 687 task.progress(20, 20); 688 task.complete(); 689 service.reset(); 690 691 assertEquals(-1, service.getProgress(), 0); 692 assertEquals(-1, service.progressProperty().get(), 0); 693 } 694 695 @Test public void callingResetInSucceededStateResetsRunningToFalse() { 696 service.start(); 697 executor.executeScheduled(); 698 task.progress(20, 20); 699 task.complete(); 700 service.reset(); 701 702 assertFalse(service.isRunning()); 703 assertFalse(service.runningProperty().get()); 704 } 705 706 @Test public void callingResetInSucceededStateResetsMessageToEmptyString() { 707 service.start(); 708 executor.executeScheduled(); 709 task.message("Message"); 710 task.progress(20, 20); 711 task.complete(); 712 service.reset(); 713 714 assertEquals("", service.getMessage()); 715 assertEquals("", service.messageProperty().get()); 716 } 717 718 @Test public void callingResetInSucceededStateResetsTitleToEmptyString() { 719 service.start(); 720 executor.executeScheduled(); 721 task.title("Title"); 722 task.progress(20, 20); 723 task.complete(); 724 service.reset(); 725 726 assertEquals("", service.getTitle()); 727 assertEquals("", service.titleProperty().get()); 728 } 729 730 @Test public void callingRestartInSucceededStateReschedules() { 731 service.start(); 732 executor.executeScheduled(); 733 task.progress(20, 20); 734 task.complete(); 735 service.restart(); 736 assertSame(Worker.State.SCHEDULED, service.getState()); 737 assertSame(Worker.State.SCHEDULED, service.stateProperty().get()); 738 } 739 740 @Test public void callingCancelInSucceededStateResultsInNoChange() { 741 service.start(); 742 executor.executeScheduled(); 743 task.progress(20, 20); 744 task.complete(); 745 service.cancel(); 746 assertSame(Worker.State.SUCCEEDED, service.getState()); 747 assertSame(Worker.State.SUCCEEDED, service.stateProperty().get()); 748 } 749 750 /*************************************************************************** 751 * * 752 * Tests for onReady * 753 * * 754 **************************************************************************/ 755 756 @Test public void onReadyPropertyNameShouldMatchMethodName() { 757 assertEquals("onReady", service.onReadyProperty().getName()); 758 } 759 760 @Test public void onReadyBeanShouldMatchService() { 761 assertSame(service, service.onReadyProperty().getBean()); 762 } 763 764 @Test public void onReadyIsInitializedToNull() { 765 assertNull(service.getOnReady()); 766 assertNull(service.onReadyProperty().get()); 767 } 768 769 @Test public void onReadyFilterCalledBefore_onReady() { 770 final AtomicBoolean filterCalled = new AtomicBoolean(false); 771 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 772 service.start(); 773 executor.executeScheduled(); 774 task.complete(); 775 service.addEventFilter(WorkerStateEvent.WORKER_STATE_READY, workerStateEvent -> filterCalled.set(true)); 776 service.setOnReady(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 777 778 // Transition to Ready state 779 service.reset(); 780 // Events should have happened 781 assertTrue(filterCalledFirst.get()); 782 } 783 784 @Test public void onReadyHandlerCalled() { 785 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 786 service.start(); 787 executor.executeScheduled(); 788 task.complete(); 789 service.addEventHandler(WorkerStateEvent.WORKER_STATE_READY, workerStateEvent -> handlerCalled.set(true)); 790 791 // Transition to Ready state 792 service.reset(); 793 // Events should have happened 794 assertTrue(handlerCalled.get()); 795 } 796 797 @Test public void removed_onReadyHandlerNotCalled() { 798 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 799 final AtomicBoolean sanity = new AtomicBoolean(false); 800 service.start(); 801 executor.executeScheduled(); 802 task.complete(); 803 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 804 service.addEventHandler(WorkerStateEvent.WORKER_STATE_READY, handler); 805 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_READY, handler); 806 service.addEventHandler(WorkerStateEvent.WORKER_STATE_READY, workerStateEvent -> sanity.set(true)); 807 808 service.reset(); 809 assertTrue(sanity.get()); 810 assertFalse(handlerCalled.get()); 811 } 812 813 @Test public void removed_onReadyFilterNotCalled() { 814 final AtomicBoolean filterCalled = new AtomicBoolean(false); 815 final AtomicBoolean sanity = new AtomicBoolean(false); 816 service.start(); 817 executor.executeScheduled(); 818 task.complete(); 819 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 820 service.addEventFilter(WorkerStateEvent.WORKER_STATE_READY, filter); 821 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_READY, filter); 822 service.addEventFilter(WorkerStateEvent.WORKER_STATE_READY, workerStateEvent -> sanity.set(true)); 823 824 service.reset(); 825 assertTrue(sanity.get()); 826 assertFalse(filterCalled.get()); 827 } 828 829 @Test public void cancelCalledFromOnReady() { 830 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 831 service.start(); 832 executor.executeScheduled(); 833 task.complete(); 834 service.addEventFilter(WorkerStateEvent.WORKER_STATE_READY, workerStateEvent -> { 835 service.cancel(); 836 }); 837 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 838 cancelNotificationCount.incrementAndGet(); 839 }); 840 841 service.reset(); 842 assertEquals(Worker.State.CANCELLED, service.getState()); 843 assertEquals(1, cancelNotificationCount.get()); 844 } 845 846 /*************************************************************************** 847 * * 848 * Tests for onScheduled * 849 * * 850 **************************************************************************/ 851 852 @Test public void onScheduledPropertyNameShouldMatchMethodName() { 853 assertEquals("onScheduled", service.onScheduledProperty().getName()); 854 } 855 856 @Test public void onScheduledBeanShouldMatchService() { 857 assertSame(service, service.onScheduledProperty().getBean()); 858 } 859 860 @Test public void onScheduledIsInitializedToNull() { 861 assertNull(service.getOnScheduled()); 862 assertNull(service.onScheduledProperty().get()); 863 } 864 865 @Test public void onScheduledFilterCalledBefore_onScheduled() { 866 final AtomicBoolean filterCalled = new AtomicBoolean(false); 867 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 868 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SCHEDULED, workerStateEvent -> filterCalled.set(true)); 869 service.setOnScheduled(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 870 871 // Transition to Scheduled state 872 service.start(); 873 executor.executeScheduled(); 874 // Events should have happened 875 assertTrue(filterCalledFirst.get()); 876 } 877 878 @Test public void scheduledCalledAfterHandler() { 879 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 880 service.setOnScheduled(workerStateEvent -> handlerCalled.set(true)); 881 882 // Transition to Scheduled state 883 service.start(); 884 executor.executeScheduled(); 885 // Events should have happened 886 assertTrue(handlerCalled.get() && factory.getCurrentTask().scheduledSemaphore.getQueueLength() == 0); 887 } 888 889 @Test public void scheduledCalledAfterHandlerEvenIfConsumed() { 890 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 891 service.setOnScheduled(workerStateEvent -> { 892 handlerCalled.set(true); 893 workerStateEvent.consume(); 894 }); 895 896 // Transition to Scheduled state 897 service.start(); 898 executor.executeScheduled(); 899 // Events should have happened 900 assertTrue(handlerCalled.get() && factory.getCurrentTask().scheduledSemaphore.getQueueLength() == 0); 901 } 902 903 @Test public void onScheduledHandlerCalled() { 904 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 905 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SCHEDULED, workerStateEvent -> handlerCalled.set(true)); 906 907 service.start(); 908 executor.executeScheduled(); 909 // Events should have happened 910 assertTrue(handlerCalled.get()); 911 } 912 913 @Test public void removed_onScheduledHandlerNotCalled() { 914 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 915 final AtomicBoolean sanity = new AtomicBoolean(false); 916 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 917 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SCHEDULED, handler); 918 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_SCHEDULED, handler); 919 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SCHEDULED, workerStateEvent -> sanity.set(true)); 920 921 service.start(); 922 executor.executeScheduled(); 923 assertTrue(sanity.get()); 924 assertFalse(handlerCalled.get()); 925 } 926 927 @Test public void removed_onScheduledFilterNotCalled() { 928 final AtomicBoolean filterCalled = new AtomicBoolean(false); 929 final AtomicBoolean sanity = new AtomicBoolean(false); 930 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 931 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SCHEDULED, filter); 932 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_SCHEDULED, filter); 933 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SCHEDULED, workerStateEvent -> sanity.set(true)); 934 935 service.start(); 936 executor.executeScheduled(); 937 assertTrue(sanity.get()); 938 assertFalse(filterCalled.get()); 939 } 940 941 @Test public void cancelCalledFromOnScheduled() { 942 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 943 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SCHEDULED, workerStateEvent -> { 944 service.cancel(); 945 }); 946 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 947 cancelNotificationCount.incrementAndGet(); 948 }); 949 950 service.start(); 951 executor.executeScheduled(); 952 assertEquals(Worker.State.CANCELLED, service.getState()); 953 assertEquals(1, cancelNotificationCount.get()); 954 } 955 956 /*************************************************************************** 957 * * 958 * Tests for onRunning * 959 * * 960 **************************************************************************/ 961 962 @Test public void onRunningPropertyNameShouldMatchMethodName() { 963 assertEquals("onRunning", service.onRunningProperty().getName()); 964 } 965 966 @Test public void onRunningBeanShouldMatchService() { 967 assertSame(service, service.onRunningProperty().getBean()); 968 } 969 970 @Test public void onRunningIsInitializedToNull() { 971 assertNull(service.getOnRunning()); 972 assertNull(service.onRunningProperty().get()); 973 } 974 975 @Test public void onRunningFilterCalledBefore_onRunning() { 976 final AtomicBoolean filterCalled = new AtomicBoolean(false); 977 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 978 service.addEventFilter(WorkerStateEvent.WORKER_STATE_RUNNING, workerStateEvent -> filterCalled.set(true)); 979 service.setOnRunning(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 980 981 // Transition to Running state 982 service.start(); 983 executor.executeScheduled(); 984 // Events should have happened 985 assertTrue(filterCalledFirst.get()); 986 } 987 988 @Test public void runningCalledAfterHandler() { 989 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 990 service.setOnRunning(workerStateEvent -> handlerCalled.set(true)); 991 992 // Transition to Running state 993 service.start(); 994 executor.executeScheduled(); 995 // Events should have happened 996 assertTrue(handlerCalled.get() && factory.getCurrentTask().runningSemaphore.getQueueLength() == 0); 997 } 998 999 @Test public void runningCalledAfterHandlerEvenIfConsumed() { 1000 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1001 service.setOnRunning(workerStateEvent -> { 1002 handlerCalled.set(true); 1003 workerStateEvent.consume(); 1004 }); 1005 1006 // Transition to Running state 1007 service.start(); 1008 executor.executeScheduled(); 1009 // Events should have happened 1010 assertTrue(handlerCalled.get() && factory.getCurrentTask().runningSemaphore.getQueueLength() == 0); 1011 } 1012 1013 @Test public void onRunningHandlerCalled() { 1014 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1015 service.addEventHandler(WorkerStateEvent.WORKER_STATE_RUNNING, workerStateEvent -> handlerCalled.set(true)); 1016 1017 service.start(); 1018 executor.executeScheduled(); 1019 // Events should have happened 1020 assertTrue(handlerCalled.get()); 1021 } 1022 1023 @Test public void removed_onRunningHandlerNotCalled() { 1024 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1025 final AtomicBoolean sanity = new AtomicBoolean(false); 1026 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 1027 service.addEventHandler(WorkerStateEvent.WORKER_STATE_RUNNING, handler); 1028 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_RUNNING, handler); 1029 service.addEventHandler(WorkerStateEvent.WORKER_STATE_RUNNING, workerStateEvent -> sanity.set(true)); 1030 1031 service.start(); 1032 executor.executeScheduled(); 1033 assertTrue(sanity.get()); 1034 assertFalse(handlerCalled.get()); 1035 } 1036 1037 @Test public void removed_onRunningFilterNotCalled() { 1038 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1039 final AtomicBoolean sanity = new AtomicBoolean(false); 1040 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 1041 service.addEventFilter(WorkerStateEvent.WORKER_STATE_RUNNING, filter); 1042 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_RUNNING, filter); 1043 service.addEventFilter(WorkerStateEvent.WORKER_STATE_RUNNING, workerStateEvent -> sanity.set(true)); 1044 1045 service.start(); 1046 executor.executeScheduled(); 1047 assertTrue(sanity.get()); 1048 assertFalse(filterCalled.get()); 1049 } 1050 1051 @Test public void cancelCalledFromOnRunning() { 1052 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 1053 service.addEventFilter(WorkerStateEvent.WORKER_STATE_RUNNING, workerStateEvent -> { 1054 service.cancel(); 1055 }); 1056 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 1057 cancelNotificationCount.incrementAndGet(); 1058 }); 1059 1060 service.start(); 1061 executor.executeScheduled(); 1062 assertEquals(Worker.State.CANCELLED, service.getState()); 1063 assertEquals(1, cancelNotificationCount.get()); 1064 } 1065 1066 /*************************************************************************** 1067 * * 1068 * Tests for onSucceeded * 1069 * * 1070 **************************************************************************/ 1071 1072 @Test public void onSucceededPropertyNameShouldMatchMethodName() { 1073 assertEquals("onSucceeded", service.onSucceededProperty().getName()); 1074 } 1075 1076 @Test public void onSucceededBeanShouldMatchService() { 1077 assertSame(service, service.onSucceededProperty().getBean()); 1078 } 1079 1080 @Test public void onSucceededIsInitializedToNull() { 1081 assertNull(service.getOnSucceeded()); 1082 assertNull(service.onSucceededProperty().get()); 1083 } 1084 1085 @Test public void onSucceededFilterCalledBefore_onSucceeded() { 1086 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1087 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 1088 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SUCCEEDED, workerStateEvent -> filterCalled.set(true)); 1089 service.setOnSucceeded(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 1090 1091 // Transition to Succeeded state 1092 service.start(); 1093 executor.executeScheduled(); 1094 task.complete(); 1095 // Events should have happened 1096 assertTrue(filterCalledFirst.get()); 1097 } 1098 1099 @Test public void succeededCalledAfterHandler() { 1100 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1101 service.setOnSucceeded(workerStateEvent -> handlerCalled.set(true)); 1102 1103 // Transition to Succeeded state 1104 service.start(); 1105 executor.executeScheduled(); 1106 task.complete(); 1107 // Events should have happened 1108 assertTrue(handlerCalled.get() && factory.getCurrentTask().succeededSemaphore.getQueueLength() == 0); 1109 } 1110 1111 @Test public void succeededCalledAfterHandlerEvenIfConsumed() { 1112 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1113 service.setOnSucceeded(workerStateEvent -> { 1114 handlerCalled.set(true); 1115 workerStateEvent.consume(); 1116 }); 1117 1118 // Transition to Succeeded state 1119 service.start(); 1120 executor.executeScheduled(); 1121 task.complete(); 1122 // Events should have happened 1123 assertTrue(handlerCalled.get() && factory.getCurrentTask().succeededSemaphore.getQueueLength() == 0); 1124 } 1125 1126 @Test public void onSucceededHandlerCalled() { 1127 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1128 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, workerStateEvent -> handlerCalled.set(true)); 1129 1130 service.start(); 1131 executor.executeScheduled(); 1132 task.complete(); 1133 // Events should have happened 1134 assertTrue(handlerCalled.get()); 1135 } 1136 1137 @Test public void removed_onSucceededHandlerNotCalled() { 1138 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1139 final AtomicBoolean sanity = new AtomicBoolean(false); 1140 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 1141 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, handler); 1142 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, handler); 1143 service.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, workerStateEvent -> sanity.set(true)); 1144 1145 service.start(); 1146 executor.executeScheduled(); 1147 task.complete(); 1148 assertTrue(sanity.get()); 1149 assertFalse(handlerCalled.get()); 1150 } 1151 1152 @Test public void removed_onSucceededFilterNotCalled() { 1153 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1154 final AtomicBoolean sanity = new AtomicBoolean(false); 1155 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 1156 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SUCCEEDED, filter); 1157 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_SUCCEEDED, filter); 1158 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SUCCEEDED, workerStateEvent -> sanity.set(true)); 1159 1160 service.start(); 1161 executor.executeScheduled(); 1162 task.complete(); 1163 } 1164 1165 @Test public void cancelCalledFromOnSucceeded() { 1166 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 1167 service.addEventFilter(WorkerStateEvent.WORKER_STATE_SUCCEEDED, workerStateEvent -> { 1168 service.cancel(); 1169 }); 1170 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 1171 cancelNotificationCount.incrementAndGet(); 1172 }); 1173 1174 service.start(); 1175 executor.executeScheduled(); 1176 task.complete(); 1177 assertEquals(Worker.State.SUCCEEDED, service.getState()); 1178 assertEquals(0, cancelNotificationCount.get()); 1179 } 1180 1181 /*************************************************************************** 1182 * * 1183 * Tests for onCancelled * 1184 * * 1185 **************************************************************************/ 1186 1187 @Test public void onCancelledPropertyNameShouldMatchMethodName() { 1188 assertEquals("onCancelled", service.onCancelledProperty().getName()); 1189 } 1190 1191 @Test public void onCancelledBeanShouldMatchService() { 1192 assertSame(service, service.onCancelledProperty().getBean()); 1193 } 1194 1195 @Test public void onCancelledIsInitializedToNull() { 1196 assertNull(service.getOnCancelled()); 1197 assertNull(service.onCancelledProperty().get()); 1198 } 1199 1200 @Test public void onCancelledFilterCalledBefore_onCancelled() { 1201 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1202 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 1203 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, workerStateEvent -> filterCalled.set(true)); 1204 service.setOnCancelled(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 1205 1206 // Transition to Cancelled state 1207 service.start(); 1208 executor.executeScheduled(); 1209 task.cancel(); 1210 // Events should have happened 1211 assertTrue(filterCalledFirst.get()); 1212 } 1213 1214 @Test public void cancelledCalledAfterHandler() { 1215 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1216 service.setOnCancelled(workerStateEvent -> handlerCalled.set(true)); 1217 1218 // Transition to Cancelled state 1219 service.start(); 1220 executor.executeScheduled(); 1221 task.cancel(); 1222 // Events should have happened 1223 assertTrue(handlerCalled.get() && factory.getCurrentTask().cancelledSemaphore.getQueueLength() == 0); 1224 } 1225 1226 @Test public void cancelledCalledAfterHandlerEvenIfConsumed() { 1227 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1228 service.setOnCancelled(workerStateEvent -> { 1229 handlerCalled.set(true); 1230 workerStateEvent.consume(); 1231 }); 1232 1233 // Transition to Cancelled state 1234 service.start(); 1235 executor.executeScheduled(); 1236 task.cancel(); 1237 // Events should have happened 1238 assertTrue(handlerCalled.get() && factory.getCurrentTask().cancelledSemaphore.getQueueLength() == 0); 1239 } 1240 1241 @Test public void onCancelledHandlerCalled() { 1242 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1243 service.addEventHandler(WorkerStateEvent.WORKER_STATE_CANCELLED, workerStateEvent -> handlerCalled.set(true)); 1244 1245 service.start(); 1246 executor.executeScheduled(); 1247 task.cancel(); 1248 // Events should have happened 1249 assertTrue(handlerCalled.get()); 1250 } 1251 1252 @Test public void removed_onCancelledHandlerNotCalled() { 1253 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1254 final AtomicBoolean sanity = new AtomicBoolean(false); 1255 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 1256 service.addEventHandler(WorkerStateEvent.WORKER_STATE_CANCELLED, handler); 1257 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_CANCELLED, handler); 1258 service.addEventHandler(WorkerStateEvent.WORKER_STATE_CANCELLED, workerStateEvent -> sanity.set(true)); 1259 1260 service.start(); 1261 executor.executeScheduled(); 1262 task.cancel(); 1263 assertTrue(sanity.get()); 1264 assertFalse(handlerCalled.get()); 1265 } 1266 1267 @Test public void removed_onCancelledFilterNotCalled() { 1268 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1269 final AtomicBoolean sanity = new AtomicBoolean(false); 1270 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 1271 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, filter); 1272 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, filter); 1273 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, workerStateEvent -> sanity.set(true)); 1274 1275 service.start(); 1276 executor.executeScheduled(); 1277 task.cancel(); 1278 assertTrue(sanity.get()); 1279 assertFalse(filterCalled.get()); 1280 } 1281 1282 @Test public void cancelCalledFromOnCancelled() { 1283 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 1284 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, workerStateEvent -> { 1285 service.cancel(); 1286 }); 1287 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 1288 cancelNotificationCount.incrementAndGet(); 1289 }); 1290 1291 service.start(); 1292 executor.executeScheduled(); 1293 task.cancel(); 1294 assertEquals(Worker.State.CANCELLED, service.getState()); 1295 assertEquals(1, cancelNotificationCount.get()); 1296 } 1297 1298 @Test public void cancelCalledFromOnFailed() { 1299 final AtomicInteger cancelNotificationCount = new AtomicInteger(); 1300 service.addEventFilter(WorkerStateEvent.WORKER_STATE_FAILED, workerStateEvent -> { 1301 service.cancel(); 1302 }); 1303 service.addEventFilter(WorkerStateEvent.WORKER_STATE_CANCELLED, event -> { 1304 cancelNotificationCount.incrementAndGet(); 1305 }); 1306 1307 service.start(); 1308 executor.executeScheduled(); 1309 task.fail(new Exception("Quit")); 1310 assertEquals(Worker.State.FAILED, service.getState()); 1311 assertEquals(0, cancelNotificationCount.get()); 1312 } 1313 1314 /*************************************************************************** 1315 * * 1316 * Tests for onFailed * 1317 * * 1318 **************************************************************************/ 1319 1320 @Test public void onFailedPropertyNameShouldMatchMethodName() { 1321 assertEquals("onFailed", service.onFailedProperty().getName()); 1322 } 1323 1324 @Test public void onFailedBeanShouldMatchService() { 1325 assertSame(service, service.onFailedProperty().getBean()); 1326 } 1327 1328 @Test public void onFailedIsInitializedToNull() { 1329 assertNull(service.getOnFailed()); 1330 assertNull(service.onFailedProperty().get()); 1331 } 1332 1333 @Test public void onFailedFilterCalledBefore_onFailed() { 1334 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1335 final AtomicBoolean filterCalledFirst = new AtomicBoolean(false); 1336 service.addEventFilter(WorkerStateEvent.WORKER_STATE_FAILED, workerStateEvent -> filterCalled.set(true)); 1337 service.setOnFailed(workerStateEvent -> filterCalledFirst.set(filterCalled.get())); 1338 1339 // Transition to Succeeded state 1340 service.start(); 1341 executor.executeScheduled(); 1342 task.fail(new Exception("The End")); 1343 // Events should have happened 1344 assertTrue(filterCalledFirst.get()); 1345 } 1346 1347 @Test public void failedCalledAfterHandler() { 1348 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1349 service.setOnFailed(workerStateEvent -> handlerCalled.set(true)); 1350 1351 // Transition to Succeeded state 1352 service.start(); 1353 executor.executeScheduled(); 1354 task.fail(new Exception("Quit Now")); 1355 // Events should have happened 1356 assertTrue(handlerCalled.get() && factory.getCurrentTask().failedSemaphore.getQueueLength() == 0); 1357 } 1358 1359 @Test public void failedCalledAfterHandlerEvenIfConsumed() { 1360 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1361 service.setOnFailed(workerStateEvent -> handlerCalled.set(true)); 1362 1363 // Transition to Succeeded state 1364 service.start(); 1365 executor.executeScheduled(); 1366 task.fail(new Exception("Quit Now")); 1367 // Events should have happened 1368 assertTrue(handlerCalled.get() && factory.getCurrentTask().failedSemaphore.getQueueLength() == 0); 1369 } 1370 1371 @Test public void onFailedHandlerCalled() { 1372 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1373 service.addEventHandler(WorkerStateEvent.WORKER_STATE_FAILED, workerStateEvent -> handlerCalled.set(true)); 1374 1375 service.start(); 1376 executor.executeScheduled(); 1377 task.fail(new Exception("Forget about it")); 1378 // Events should have happened 1379 assertTrue(handlerCalled.get()); 1380 } 1381 1382 @Test public void removed_onFailedHandlerNotCalled() { 1383 final AtomicBoolean handlerCalled = new AtomicBoolean(false); 1384 final AtomicBoolean sanity = new AtomicBoolean(false); 1385 EventHandler<WorkerStateEvent> handler = workerStateEvent -> handlerCalled.set(true); 1386 service.addEventHandler(WorkerStateEvent.WORKER_STATE_FAILED, handler); 1387 service.removeEventHandler(WorkerStateEvent.WORKER_STATE_FAILED, handler); 1388 service.addEventHandler(WorkerStateEvent.WORKER_STATE_FAILED, workerStateEvent -> sanity.set(true)); 1389 1390 service.start(); 1391 executor.executeScheduled(); 1392 task.fail(new Exception("Quit")); 1393 assertTrue(sanity.get()); 1394 assertFalse(handlerCalled.get()); 1395 } 1396 1397 @Test public void removed_onFailedFilterNotCalled() { 1398 final AtomicBoolean filterCalled = new AtomicBoolean(false); 1399 final AtomicBoolean sanity = new AtomicBoolean(false); 1400 EventHandler<WorkerStateEvent> filter = workerStateEvent -> filterCalled.set(true); 1401 service.addEventFilter(WorkerStateEvent.WORKER_STATE_FAILED, filter); 1402 service.removeEventFilter(WorkerStateEvent.WORKER_STATE_FAILED, filter); 1403 service.addEventFilter(WorkerStateEvent.WORKER_STATE_FAILED, workerStateEvent -> sanity.set(true)); 1404 1405 service.start(); 1406 executor.executeScheduled(); 1407 task.fail(new Exception("Quit")); 1408 assertTrue(sanity.get()); 1409 assertFalse(filterCalled.get()); 1410 } 1411 1412 /*************************************************************************** 1413 * * 1414 * Tests that invoking methods from the wrong thread leads to errors, and * 1415 * that regardless of which thread starts the Service, all notification * 1416 * (events, etc) happen on the FX thread only. * 1417 * * 1418 **************************************************************************/ 1419 1420 @Test public void canCreateServiceOnRandomThread() { 1421 RandomThread random = new RandomThread(() -> { 1422 DoNothingService s = null; 1423 try { 1424 s = new DoNothingService(); 1425 } finally { 1426 if (s != null) s.shutdown(); 1427 } 1428 }); 1429 random.test(); 1430 } 1431 1432 @Test public void canGetReferencesToPropertiesOnRandomThread() { 1433 RandomThread random = new RandomThread(() -> { 1434 DoNothingService s = null; 1435 try { 1436 s = new DoNothingService(); 1437 s.exceptionProperty(); 1438 s.executorProperty(); 1439 s.messageProperty(); 1440 s.progressProperty(); 1441 s.onCancelledProperty(); 1442 s.onFailedProperty(); 1443 s.onReadyProperty(); 1444 s.onRunningProperty(); 1445 s.onScheduledProperty(); 1446 s.onSucceededProperty(); 1447 s.runningProperty(); 1448 s.stateProperty(); 1449 s.titleProperty(); 1450 s.totalWorkProperty(); 1451 s.valueProperty(); 1452 s.workDoneProperty(); 1453 } finally { 1454 if (s != null) s.shutdown(); 1455 } 1456 }); 1457 random.test(); 1458 } 1459 1460 @Test public void canInvokeGettersOnRandomThread() { 1461 RandomThread random = new RandomThread(() -> { 1462 DoNothingService s = null; 1463 try { 1464 s = new DoNothingService(); 1465 s.getException(); 1466 s.getExecutor(); 1467 s.getMessage(); 1468 s.getProgress(); 1469 s.getOnCancelled(); 1470 s.getOnFailed(); 1471 s.getOnReady(); 1472 s.getOnRunning(); 1473 s.getOnScheduled(); 1474 s.getOnSucceeded(); 1475 s.isRunning(); 1476 s.getState(); 1477 s.getTitle(); 1478 s.getTotalWork(); 1479 s.getValue(); 1480 s.getWorkDone(); 1481 } finally { 1482 if (s != null) s.shutdown(); 1483 } 1484 }); 1485 random.test(); 1486 } 1487 1488 @Test public void canInvokeSettersOnRandomThread() { 1489 RandomThread random = new RandomThread(() -> { 1490 DoNothingService s = null; 1491 try { 1492 s = new DoNothingService(); 1493 ServiceShim.setEventHandler(s, WorkerStateEvent.ANY, event -> { 1494 }); 1495 s.setOnCancelled(event -> { 1496 }); 1497 s.setOnFailed(event -> { 1498 }); 1499 s.setOnReady(event -> { 1500 }); 1501 s.setOnRunning(event -> { 1502 }); 1503 s.setOnScheduled(event -> { 1504 }); 1505 s.setOnSucceeded(event -> { 1506 }); 1507 } finally { 1508 if (s != null) s.shutdown(); 1509 } 1510 }); 1511 random.test(); 1512 } 1513 1514 @Test public void canInvokeStartOnRandomThread() { 1515 RandomThread random = new RandomThread(() -> { 1516 DoNothingService s = null; 1517 try { 1518 s = new DoNothingService(); 1519 s.start(); 1520 } finally { 1521 if (s != null) s.shutdown(); 1522 } 1523 }); 1524 random.test(); 1525 } 1526 1527 @Test (expected = IllegalStateException.class) 1528 public void cannotInvokeRestartOnRandomThreadAfterStart() throws Throwable { 1529 assertThrowsException(s -> s.restart()); 1530 } 1531 1532 @Test (expected = IllegalStateException.class) 1533 public void cannotInvokeCancelOnRandomThreadAfterStart() throws Throwable { 1534 assertThrowsException(s -> { 1535 s.cancel(); 1536 }); 1537 } 1538 1539 @Test (expected = IllegalStateException.class) 1540 public void cannotInvokeSettersOnRandomThreadAfterStart_1() throws Throwable { 1541 assertThrowsException(s -> 1542 ServiceShim.setEventHandler(s, WorkerStateEvent.ANY, event -> { 1543 })); 1544 } 1545 1546 @Test (expected = IllegalStateException.class) 1547 public void cannotInvokeSettersOnRandomThreadAfterStart_2() throws Throwable { 1548 assertThrowsException(s -> s.setOnCancelled(event -> { 1549 })); 1550 } 1551 1552 @Test (expected = IllegalStateException.class) 1553 public void cannotInvokeSettersOnRandomThreadAfterStart_3() throws Throwable { 1554 assertThrowsException(s -> s.setOnFailed(event -> { })); 1555 } 1556 1557 @Test (expected = IllegalStateException.class) 1558 public void cannotInvokeSettersOnRandomThreadAfterStart_4() throws Throwable { 1559 assertThrowsException(s -> s.setOnReady(event -> { })); 1560 } 1561 1562 @Test (expected = IllegalStateException.class) 1563 public void cannotInvokeSettersOnRandomThreadAfterStart_5() throws Throwable { 1564 assertThrowsException(s -> s.setOnRunning(event -> { })); 1565 } 1566 1567 @Test (expected = IllegalStateException.class) 1568 public void cannotInvokeSettersOnRandomThreadAfterStart_6() throws Throwable { 1569 assertThrowsException(s -> s.setOnScheduled(event -> { 1570 })); 1571 } 1572 1573 @Test (expected = IllegalStateException.class) 1574 public void cannotInvokeSettersOnRandomThreadAfterStart_7() throws Throwable { 1575 assertThrowsException(s -> s.setOnSucceeded(event -> { })); 1576 } 1577 1578 @Test (expected = IllegalStateException.class) 1579 public void cannotInvokeGettersOnRandomThreadAfterStart_1() throws Throwable { 1580 assertThrowsException(s -> { 1581 s.getException(); 1582 }); 1583 } 1584 1585 @Test (expected = IllegalStateException.class) 1586 public void cannotInvokeGettersOnRandomThreadAfterStart_2() throws Throwable { 1587 assertThrowsException(s -> { 1588 s.getExecutor(); 1589 }); 1590 } 1591 1592 @Test (expected = IllegalStateException.class) 1593 public void cannotInvokeGettersOnRandomThreadAfterStart_3() throws Throwable { 1594 assertThrowsException(s -> { 1595 s.getMessage(); 1596 }); 1597 } 1598 1599 @Test (expected = IllegalStateException.class) 1600 public void cannotInvokeGettersOnRandomThreadAfterStart_4() throws Throwable { 1601 assertThrowsException(s -> { 1602 s.getProgress(); 1603 }); 1604 } 1605 1606 @Test (expected = IllegalStateException.class) 1607 public void cannotInvokeGettersOnRandomThreadAfterStart_5() throws Throwable { 1608 assertThrowsException(s -> { 1609 s.getOnCancelled(); 1610 }); 1611 } 1612 1613 @Test (expected = IllegalStateException.class) 1614 public void cannotInvokeGettersOnRandomThreadAfterStart_6() throws Throwable { 1615 assertThrowsException(s -> { 1616 s.getOnFailed(); 1617 }); 1618 } 1619 1620 @Test (expected = IllegalStateException.class) 1621 public void cannotInvokeGettersOnRandomThreadAfterStart_7() throws Throwable { 1622 assertThrowsException(s -> { 1623 s.getOnReady(); 1624 }); 1625 } 1626 1627 @Test (expected = IllegalStateException.class) 1628 public void cannotInvokeGettersOnRandomThreadAfterStart_8() throws Throwable { 1629 assertThrowsException(s -> { 1630 s.getOnRunning(); 1631 }); 1632 } 1633 1634 @Test (expected = IllegalStateException.class) 1635 public void cannotInvokeGettersOnRandomThreadAfterStart_9() throws Throwable { 1636 assertThrowsException(s -> { 1637 s.getOnScheduled(); 1638 }); 1639 } 1640 1641 @Test (expected = IllegalStateException.class) 1642 public void cannotInvokeGettersOnRandomThreadAfterStart_10() throws Throwable { 1643 assertThrowsException(s -> { 1644 s.getOnSucceeded(); 1645 }); 1646 } 1647 1648 @Test (expected = IllegalStateException.class) 1649 public void cannotInvokeGettersOnRandomThreadAfterStart_11() throws Throwable { 1650 assertThrowsException(s -> { 1651 s.isRunning(); 1652 }); 1653 } 1654 1655 @Test (expected = IllegalStateException.class) 1656 public void cannotInvokeGettersOnRandomThreadAfterStart_12() throws Throwable { 1657 assertThrowsException(s -> { 1658 s.getState(); 1659 }); 1660 } 1661 1662 @Test (expected = IllegalStateException.class) 1663 public void cannotInvokeGettersOnRandomThreadAfterStart_13() throws Throwable { 1664 assertThrowsException(s -> { 1665 s.getTitle(); 1666 }); 1667 } 1668 1669 @Test (expected = IllegalStateException.class) 1670 public void cannotInvokeGettersOnRandomThreadAfterStart_14() throws Throwable { 1671 assertThrowsException(s -> { 1672 s.getTotalWork(); 1673 }); 1674 } 1675 1676 @Test (expected = IllegalStateException.class) 1677 public void cannotInvokeGettersOnRandomThreadAfterStart_15() throws Throwable { 1678 assertThrowsException(s -> { 1679 s.getValue(); 1680 }); 1681 } 1682 1683 @Test (expected = IllegalStateException.class) 1684 public void cannotInvokeGettersOnRandomThreadAfterStart_16() throws Throwable { 1685 assertThrowsException(s -> { 1686 s.getValue(); 1687 }); 1688 } 1689 1690 @Test (expected = IllegalStateException.class) 1691 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_1() throws Throwable { 1692 assertThrowsException(s -> { 1693 s.exceptionProperty(); 1694 }); 1695 } 1696 1697 @Test (expected = IllegalStateException.class) 1698 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_2() throws Throwable { 1699 assertThrowsException(s -> { 1700 s.executorProperty(); 1701 }); 1702 } 1703 1704 @Test (expected = IllegalStateException.class) 1705 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_3() throws Throwable { 1706 assertThrowsException(s -> { 1707 s.messageProperty(); 1708 }); 1709 } 1710 1711 @Test (expected = IllegalStateException.class) 1712 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_4() throws Throwable { 1713 assertThrowsException(s -> { 1714 s.progressProperty(); 1715 }); 1716 } 1717 1718 @Test (expected = IllegalStateException.class) 1719 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_5() throws Throwable { 1720 assertThrowsException(s -> { 1721 s.onCancelledProperty(); 1722 }); 1723 } 1724 1725 @Test (expected = IllegalStateException.class) 1726 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_6() throws Throwable { 1727 assertThrowsException(s -> { 1728 s.onFailedProperty(); 1729 }); 1730 } 1731 1732 @Test (expected = IllegalStateException.class) 1733 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_7() throws Throwable { 1734 assertThrowsException(s -> { 1735 s.onReadyProperty(); 1736 }); 1737 } 1738 1739 @Test (expected = IllegalStateException.class) 1740 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_8() throws Throwable { 1741 assertThrowsException(s -> { 1742 s.onRunningProperty(); 1743 }); 1744 } 1745 1746 @Test (expected = IllegalStateException.class) 1747 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_9() throws Throwable { 1748 assertThrowsException(s -> { 1749 s.onScheduledProperty(); 1750 }); 1751 } 1752 1753 @Test (expected = IllegalStateException.class) 1754 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_10() throws Throwable { 1755 assertThrowsException(s -> { 1756 s.onSucceededProperty(); 1757 }); 1758 } 1759 1760 @Test (expected = IllegalStateException.class) 1761 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_11() throws Throwable { 1762 assertThrowsException(s -> { 1763 s.runningProperty(); 1764 }); 1765 } 1766 1767 @Test (expected = IllegalStateException.class) 1768 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_12() throws Throwable { 1769 assertThrowsException(s -> { 1770 s.stateProperty(); 1771 }); 1772 } 1773 1774 @Test (expected = IllegalStateException.class) 1775 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_13() throws Throwable { 1776 assertThrowsException(s -> { 1777 s.titleProperty(); 1778 }); 1779 } 1780 1781 @Test (expected = IllegalStateException.class) 1782 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_14() throws Throwable { 1783 assertThrowsException(s -> { 1784 s.totalWorkProperty(); 1785 }); 1786 } 1787 1788 @Test (expected = IllegalStateException.class) 1789 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_15() throws Throwable { 1790 assertThrowsException(s -> { 1791 s.valueProperty(); 1792 }); 1793 } 1794 1795 @Test (expected = IllegalStateException.class) 1796 public void cannotInvokePropertyGettersOnRandomThreadAfterStart_16() throws Throwable { 1797 assertThrowsException(s -> { 1798 s.workDoneProperty(); 1799 }); 1800 } 1801 1802 private void assertThrowsException(final ServiceTestExecution c) throws Throwable { 1803 RandomThread random = new RandomThread(() -> { 1804 DoNothingService s = null; 1805 try { 1806 s = new DoNothingService(); 1807 s.start(); 1808 c.test(s); 1809 } finally { 1810 if (s != null) s.shutdown(); 1811 } 1812 }); 1813 1814 try { 1815 random.test(); 1816 } catch (AssertionError er) { 1817 throw er.getCause(); 1818 } 1819 } 1820 1821 private interface ServiceTestExecution { 1822 public void test(DoNothingService s); 1823 } 1824 1825 /** 1826 * Specialized thread used for checking access to various methods from a "random thread" other 1827 * than the FX thread. This class has built into it all the supported needed for handling 1828 * exceptions and so forth, such that assertion errors are raised if an exception occurs 1829 * on the thread, and also handles blocking until the thread body concludes. 1830 */ 1831 private static final class RandomThread extends Thread { 1832 private final CountDownLatch testCompleted = new CountDownLatch(1); 1833 private Throwable error; 1834 1835 public RandomThread(Runnable target) { 1836 super(target); 1837 } 1838 1839 @Override public void run() { 1840 try { 1841 super.run(); 1842 } catch (Throwable th) { 1843 error = th; 1844 } finally { 1845 testCompleted.countDown(); 1846 } 1847 } 1848 1849 public void test() throws AssertionError { 1850 start(); 1851 try { 1852 testCompleted.await(); 1853 } catch (InterruptedException e) { 1854 throw new AssertionError("Test did not complete normally"); 1855 } 1856 if (error != null) { 1857 throw new AssertionError(error); 1858 } 1859 } 1860 } 1861 1862 /** 1863 * A service which does absolutely nothing and isn't hardwired to believe that 1864 * the test thread is the FX thread (unlike the other services in these tests) 1865 */ 1866 private static final class DoNothingService extends ServiceShim { 1867 private Thread pretendFXThread; 1868 private ConcurrentLinkedQueue<Runnable> eventQueue = new ConcurrentLinkedQueue<>(); 1869 private volatile boolean shutdown = false; 1870 1871 public DoNothingService() { 1872 setExecutor(command -> { 1873 Thread backgroundThread = new Thread(command); 1874 backgroundThread.start(); 1875 }); 1876 } 1877 1878 void shutdown() { 1879 shutdown = true; 1880 } 1881 1882 @Override protected Task createTask() { 1883 return new TaskShim() { 1884 @Override protected Object call() throws Exception { 1885 return null; 1886 } 1887 1888 @Override public boolean isFxApplicationThread() { 1889 return Thread.currentThread() == pretendFXThread; 1890 } 1891 1892 @Override 1893 public void runLater(Runnable r) { 1894 DoNothingService.this.runLater(r); 1895 } 1896 }; 1897 } 1898 1899 @Override public void runLater(Runnable r) { 1900 eventQueue.add(r); 1901 if (pretendFXThread == null) { 1902 pretendFXThread = new Thread() { 1903 @Override public void run() { 1904 while (!shutdown) { 1905 Runnable event = eventQueue.poll(); 1906 if (event != null) { 1907 event.run(); 1908 } 1909 } 1910 } 1911 }; 1912 pretendFXThread.start(); 1913 } 1914 } 1915 1916 @Override public boolean isFxApplicationThread() { 1917 return Thread.currentThread() == pretendFXThread; 1918 } 1919 } 1920 1921 /*************************************************************************** 1922 * * 1923 * A mythical subclass should be able to set an event handler and * 1924 * have events fired on the Service work. * 1925 * * 1926 **************************************************************************/ 1927 1928 @Test public void eventFiredOnSubclassWorks() { 1929 final AtomicBoolean result = new AtomicBoolean(false); 1930 TestServiceFactory factory = new TestServiceFactory() { 1931 @Override public AbstractTask createTestTask() { 1932 return new SimpleTask(); 1933 } 1934 1935 @Override public Service<String> createService() { 1936 MythicalService svc = new MythicalService(); 1937 svc.setHandler(mythicalEvent -> result.set(true)); 1938 ServiceShim.fireEvent(svc, new MythicalEvent()); 1939 return svc; 1940 } 1941 }; 1942 Service<String> svc = factory.createService(); 1943 svc.start(); 1944 assertTrue(result.get()); 1945 } 1946 1947 private static final class MythicalService extends ServiceShim<String> { 1948 public void setHandler(EventHandler<MythicalEvent> h) { 1949 ServiceShim.setEventHandler(this, MythicalEvent.ANY, h); 1950 } 1951 1952 @Override protected Task<String> createTask() { 1953 return new SimpleTask(); 1954 } 1955 1956 @Override public void checkThread() { } 1957 1958 @Override public void runLater(Runnable r) { 1959 r.run(); 1960 } 1961 } 1962 }