-
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
With 1.6 where is a PersistentTaskTestService
and other helper methods like:
- runNextTrigger
- scheduleNextTriggersAndWait
<dependency>
<groupId>org.sterl.spring</groupId>
<artifactId>spring-persistent-tasks-test</artifactId>
<version>1.x.x</version>
</dependency>
You may either include it in the component scan or build it manually in your test config:
@TestConfiguration
static class Config {
@Bean
PersistentTaskTestService persistentTaskTestService(List<SchedulerService> schedulers, TriggerService triggerService) {
return new PersistentTaskTestService(schedulers, triggerService);
}
}
This class adds some test methods to wait, run or assert triggers.
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
}