-
Notifications
You must be signed in to change notification settings - Fork 0
JUnit Tests Triggers and Tasks
The SchedulerService
can be disabled for unit testing, which ensures that no trigger will be
executed automatically.
spring:
persistent-tasks:
scheduler-enabled: false
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 next pending trigger synchronously
triggerService.run(triggerService.lockNextTrigger("test"));
// THEN
// any asserts you might need
}
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;
/**
* Run all pending triggers synchronously
*/
protected int waitForDbSchedulerTasks() {
TriggerEntity t;
int count = 0;
while ((t = triggerService.lockNextTrigger("test")) != null) {
triggerService.run(t);
++count;
}
return count;
}
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;
}
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 // if more than one
@Bean
SchedulerService schedulerService(
TriggerService triggerService,
EditSchedulerStatusComponent editSchedulerStatus,
TransactionTemplate trx) {
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 asynchronously - but with and wait
var triggerKeys = persistentTaskService.executeTriggersAndWait();
// OR queue all triggers asynchronously - and return the futures
var futureTriggerKeys = persistentTaskService.executeTriggers();
// THEN
// any asserts you might need
}
In some cases we have longer running triggers which may trigger new jobs. As so we have to wait.
Awaitility.await().atMost(Duration.ofMillis(1500)).until(() -> { // set the max wait time as needed
waitForDbSchedulerTasks();
return //* insert here your assert for the last task you wait for */;
});
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
}