Skip to content

Triggers and Tasks in JUnit Tests

Paul Sterl edited this page Jan 7, 2025 · 5 revisions

Disable SchedulerService

The SchedulerService can be disabled for unit testing, which ensures that no trigger will be executed automatically.

spring:
    persistent-tasks:
        scheduler-enabled: false

Manually run one task

Now you can run any trigger manually using the TriggerService

NOTE: Using the TriggerService is recommended to see any errors which might arise.

    @Autowired
    private TriggerService triggerService;

    @Test
    void testRunTriggerDirectly() {
        // GIVEN
        // setup your test and create any triggers needed
        var trigger = TaskTriggerBuilder
                .<Vehicle>newTrigger("task2")
                .id("my-id") // will overwrite existing triggers
                .state(new Vehicle("funny"))
                .build();

        // WHEN create and directly run this trigger
        triggerService.run(triggerService.queue(trigger));

        // THEN
        // any asserts you might need
    }

    @Test
    void testRunUnknownTriggersCreated() {
        // GIVEN
        // setup your test call any method which might create triggers

        // WHEN run any pending triggers
        triggerService.run(triggerService.lockNextTrigger("test"));

        // THEN
        // any asserts you might need
    }

Run all queued tasks

Sometimes it might be useful quickly to execute all running tasks. This sample adds a method e.g. to your base test class which will trigger any task which is now due to be executed.

  @Autowired
  protected TriggerService triggerService;

  protected int waitForDbSchedulerTasks() {
    TriggerEntity t;
    int count = 0;
    while ((t = triggerService.lockNextTrigger("test")) != null) {
      triggerService.run(t);
      ++count;
    }
    return count;
  }

Run all queued tasks in the future & retries

A common use case is run tasks which should run in the future or just to wait that all retries are exceeded.

  @Autowired
  protected TriggerService triggerService;

  protected int waitForDbSchedulerTasks(OffsetDateTime thenToRun) {
    List<TriggerEntity> triggers;
    int count = 0;
    while (!(triggers = triggerService.lockNextTrigger("test", 1, thenToRun)).isEmpty()) {
      triggerService.run(triggers.get(0));
      ++count;
    }
    return count;
  }

Async execution of Triggers

It is also possible to define a test scheduler and use the async way to execute any triggers (without the spring scheduler which would trigger them automatically).

NOTE: Any errors are now in the log and are handled by the framework with retries etc.

    @Configuration
    public static class TestConfig {

        @Primary
        @SuppressWarnings("resource")
        SchedulerService schedulerService(TriggerService triggerService, EditSchedulerStatusComponent editSchedulerStatus,
                TransactionTemplate trx) throws UnknownHostException {

            final var taskExecutor = new TaskExecutorComponent(triggerService, 10);
            taskExecutor.setMaxShutdownWaitTime(Duration.ofSeconds(0));
            return new SchedulerService("testScheduler", triggerService, taskExecutor, editSchedulerStatus, trx);
        }
    }

Now the PersistentTaskService has a method to trigger or to trigger and to wait for the result:

    @Autowired
    private PersistentTaskService persistentTaskService;

    @Test
    void testFoo() {
        // GIVEN
        // setup your test and create any triggers needed

        // WHEN run any pending triggers
        persistentTaskService.executeTriggersAndWait();

        // THEN
        // any asserts you might need
    }

During the setup and cleanup it is possible to cancel any pending triggers:

    @BeforeEach
    public void beforeEach() throws Exception {
        triggerService.deleteAll();
        historyService.deleteAll();
        schedulerService.setMaxThreads(10);
        schedulerService.start();
    }

    @AfterEach
    public void afterEach() throws Exception {
        // will cancel any pending tasks
        schedulerService.shutdownNow(); // use .stop() if you want to wait
    }