0

I have a following flow implemented in Spring Integration DSL:

  1. Take feed from HTTP
  2. Enrich errorChannel header (point of handling all exception downstream here).
  3. Transform message to be a Collection
  4. Split Collection into sepearate messages
  5. Send each message to next processing channels
@Bean
    public IntegrationFlow inboundHttpFlow(
        Puller puller,
        HeaderEnricher errorHandlingChannelHeaderEnricher,
        FeedTransformer feedTransformer,
        MessageChannel outputFeedIntegrationChannel
    ) {
        final Consumer<SourcePollingChannelAdapterSpec> pollingSpec = spec ->
            spec
                .poller(Pollers.cron(SCHEDULE_EVERY_HALF_MINUTE)
                    .errorChannel(INBOUND_ERROR_CHANNEL));

        return IntegrationFlows
            .from(puller, pollingSpec)
            .enrichHeaders(errorHandlingChannelHeaderEnricher)
            .transform(feedTransformer)
            .split()
            .channel(outputFeedIntegrationChannel)
            .get();
    }

Where my errorHandlingChannelHeaderEnricher is:

@Component
public class ErrorHandlingChannelHeaderEnricher implements HeaderEnricher {
    @Override
    public void accept(HeaderEnricherSpec spec) {
        spec.header(
            MessageHeaders.ERROR_CHANNEL,
            INBOUND_ERROR_CHANNEL,
            true
        );
    }
}

When feedTransformer throws an exception in working app then it goes to set errorChannel as expected. But I don't know how to write a test to test if thrown exception goes to errorChannel defined in header?

When I'm trying to simulate it in test given way, it doesn't work because exception is thrown back into caller instead of errorChannel:

// given
Throwable transformerException = new IllegalStateException();
when(feedTransformerMock.apply(any())).thenThrow(transformerException);

// when
var testFeedMessage = MessageBuilder
    .withPayload(pullerResult)
    .build();

inboundHttpFlow.getInputChannel().send(testFeedMessage); // excetpion returns to caller here

// then
verify(errorHandlerSpy).accept(transformerException);

And exception is typical:

org.springframework.integration.transformer.MessageTransformationException: Failed to transform Message; nested exception is org.springframework.messaging.MessageHandlingException: nested exception is java.lang.IllegalStateException, failedMessage=GenericMessage [payload=test-payload, headers={errorChannel=inboundErrorChannel, id=f77a6a01-9bca-5af3-8352-7edb4c5e94b0, timestamp=1556019833867}]
, failedMessage=GenericMessage [payload=test-payload, headers={errorChannel=inboundErrorChannel, id=f77a6a01-9bca-5af3-8352-7edb4c5e94b0, timestamp=1556019833867}]

I assume that because of DirectChannel and lack of poller in this test example in compare to real flow (with poller). Is there any way to simulate that throwing exception and checking if it really goes to errorChannel defined in header?

Łukasz Gawron
  • 897
  • 10
  • 20
Arkadiusz Migała
  • 927
  • 1
  • 8
  • 14

1 Answers1

1

It's not clear what you are trying to test.

Why do you need to test the framework?

You don't need to enrich the headers since you already have an error channel on the poller.

You are correct; sending to a DirectChannel will result in the exception being thrown to the caller.

If you really want to test the framework, mock the Puller instead of sending to the input channel.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks for the reply. I don't want to test framework. I have my custom Error Handler which is used as Message Handler in my error flow that triggers on errorChannel which is innboundErrorChannel in that case. In that integration test i want to make sure that my Error Handler will handle exception in integration flow (e.g. during transformation). I was looking for a way to trigger that flow in tests because in real it's polled by cron Poller, on which i have to wait. Mocking Puller is fine but how to trigger it? I was also thinking about adding additional channel here between. – Arkadiusz Migała Apr 23 '19 at 13:53
  • If you just want to test your error flow, why not just build an `ErrroMessage` (with a `MessagingException` payload with a `failedMessage`) and send it to `INBOUND_ERROR_CHANNEL`. You could also make the poller a `@Bean` and replace it with a simple on in the test case. – Gary Russell Apr 23 '19 at 14:29
  • The reason is because I want to test error flow in integration test to be sure that exceptions that occur in flow will be handled by my error handler (global point of handling them in that flow). Injecting Poller may be good idea but how can I make the poller simple and force it to start when the test starts and avoid returning exception back to the caller? – Arkadiusz Migała Apr 24 '19 at 10:11
  • Just replace the cron poller bean with a fixedRate poller bean. – Gary Russell Apr 24 '19 at 13:15