I have a Spring Integration flow that makes use of a MessageSource
to periodically populate messages from a database query (no, I didn't intend to use Spring Integration JPA/JDBC)
@Bean
public IntegrationFlow messageTimeout(
ReadTimeoutsMessageSource readTimeoutsMessageSource,
UpdatePaymentWithStatusTimeoutHandler updatePaymentWithStatusTimeoutHandler
) {
return IntegrationFlow
/*
* Read from OraIpTask procedure
*/
.from(readTimeoutsMessageSource, s -> s
.id("messageTimeout.readTimeouts")
.poller(Pollers.fixedDelay(Duration.ofMinutes(1), Duration.ofSeconds(10)))
)
.split(s -> s.requiresReply(false))
.bridge(b -> b
.id("messageTimeout.bridge")
.taskScheduler(messageTimeoutScheduler())
)
/*
* Log a warning
*/
.log(LoggingHandler.Level.WARN, dto -> "Found timeout: " + dto)
/*
Update Payment with status timeout
*/
.handle(updatePaymentWithStatusTimeoutHandler, h -> h.id("updatePaymentWithStatusTimeoutFlow.updatePaymentWithStatusTimeout"))
/*
Discard the message
*/
.nullChannel();
}
Let's go to the point: the poller has an initial delay of 10 seconds, and in the Junit tests for this flow I don't want to wait precious time.
The test mocks a stored procedure to return data, and I expect that a message is constructed accordingly. I just want to test that every row in the Message is consumed by the final handler
without having to wait.
Is there a way to tell Spring to kick-start the poller instantly during the test and/or run it once?
As an alternative, I could construct the message on my own and use MockIntegrationContext.substituteMessageSourceFor
with the mock message. I haven't tried it yet. I am asking to learn more about Spring Integration and the cleanest way to perform automated testing
Thanks for advice!
The way to do that right now is like this:
You mark your test class with @SpringIntegrationTest(noAutoStartup ="messageTimeout.readTimeouts")
.
Even if you don't use mocks, you still would like to have a control over that SourcePollingChannelAdapter
lifecycle: prepare the procedure and respective trigger for the poller. So, it is better to have that endpoint stopped before you are ready in the test.
The you do in the test class:
@Autowired
@Qualifier("messageTimeout.readTimeouts")
SourcePollingChannelAdapter readTimeoutsEndpoint;
In the test method (or how you prepare your test data) you do:
this.readTimeoutsEndpoint.setTrigger(new OnlyOnceTrigger());
this.readTimeoutsEndpoint.start();
And consumption of your data is going to happen immediately.
I think we can introduce something like MockIntegrationContext.substituteTriggerFor(String pollingAdapterId, Trigger trigger, boolean autoStartup)
to make it obvious.
Feel free to raise a GH issue for that! For now I believe the solution you gave you is what you are looking for.