Reputation: 1554
I'm trying to mock a failure of an outbound gateway in a unit test like this:
MessageHandler mockCognitiveAnalyze =
mockMessageHandler().handleNextAndReply(m -> ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
this.mockIntegrationContext.substituteMessageHandlerFor("cognitiveServicesReadEndpoint", mockCognitiveAnalyze);
What I would expect is that when the cognitiveServicesReadEndpoint is invoked, it won't succeed and the flow should be finished (or in my case, a retry advice is applied so it should be repeated). But what happens is, no exception or error will be thrown and the next handle is invoked. The flow looks like this:
.handle(Http.outboundGateway(cognitiveServicesUri + "/vision/v3.0/read/analyze")
.mappedRequestHeaders("Ocp-Apim-Subscription-Key")
.mappedResponseHeaders("Operation-Location"),
c -> c.advice(this.advices.retryAdvice())
.id("cognitiveServicesReadEndpoint"))
.transform(p -> "")
.handle(Http.outboundGateway(h -> h.getHeaders().get("Operation-Location"))
.mappedRequestHeaders("Ocp-Apim-Subscription-Key")
.httpMethod(HttpMethod.GET)
.expectedResponseType(String.class), this.advices.ocrSpec())
Any idea how can I setup the mock handler to properly throw an exception?
Side note: .transform(p -> "") is needed for proper handling of the headers, see Spring Integration HTTP Outbound Gateway header not forwarder on a consecutive request
UPDATE1
This is how the handler looks at the moment:
.handle(Http.outboundGateway(h -> String.format("%s%s", uri, h.getHeaders()
.get(CustomHeaders.DOCUMENT_ID.name())))
.httpMethod(HttpMethod.GET)
.expectedResponseType(byte[].class), c -> c.advice(this.advices.retryAdvice())
.id("endpoint1"))
.wireTap(sf -> sf.enrichHeaders(h -> h.header("ocp-apim-subscription-key", computerVisionApiKey))
.handle(Http.outboundGateway(cognitiveServicesUri + "/vision/v3.0/read/analyze")
.mappedRequestHeaders("Ocp-Apim-Subscription-Key")
.mappedResponseHeaders("Operation-Location"),
c -> c.advice(this.advices.retryAdvice())
.id("cognitiveServicesReadEndpoint"))
And the testing code:
MessageHandler mockCognitiveAnalyze = mockMessageHandler().handleNext(m -> {
throw new HttpClientErrorException(HttpStatus.UNAUTHORIZED);
});
this.mockIntegrationContext.substituteMessageHandlerFor("cognitiveServicesReadEndpoint",
mockCognitiveAnalyze);
Upvotes: 0
Views: 405
Reputation: 121542
The MockMessageHandler.handleNextAndReply()
provides a Function
which is invoked in the handleMessageInternal()
. Since there is no interaction with the Resttemplate
(you fully substitute it), your HttpStatus.UNAUTHORIZED
is not translated into an exception.
You probably should simulate a RestTemplate
logic on the matter in that your handleNextAndReply()
and throw respective exception instead.
The RestTemplate
has the logic like this:
protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
ResponseErrorHandler errorHandler = getErrorHandler();
boolean hasError = errorHandler.hasError(response);
if (logger.isDebugEnabled()) {
try {
int code = response.getRawStatusCode();
HttpStatus status = HttpStatus.resolve(code);
logger.debug("Response " + (status != null ? status : code));
}
catch (IOException ex) {
// ignore
}
}
if (hasError) {
errorHandler.handleError(url, method, response);
}
}
So, you need to borrow and idea from the errorHandler
which is a DefaultResponseErrorHandler
and can throw respective exception from the provided ClientHttpResponse
. Or you just can go ahead and throw an HttpClientErrorException.Unauthorized
directly.
UPDATE
Something like this:
MockMessageHandler mockMessageHandler = mockMessageHandler();
mockMessageHandler.handleNext(message -> {
throw new HttpClientErrorException.create(...);
});
this.mockIntegrationContext.substituteMessageHandlerFor("httpGateway", mockMessageHandler);
Upvotes: 2
Reputation: 1554
This is a final solution:
MessageHandler mockCognitiveAnalyze = mockMessageHandler().handleNextAndReply(m -> {
throw new HttpClientErrorException(HttpStatus.UNAUTHORIZED);
});
Upvotes: 1