我正在尝试编写简单的单元测试,验证 Camel 路由是否配置正确以及是否真正进行了重新传递尝试。我有这个路线构建器实现:
class LocalEndpoint extends RouteBuilder {
private final CamelContext camelContext;
private final String targetEndpoint;
public LocalEndpoint(CamelContext camelContext, String targetEndpoint) {
super(camelContext);
this.camelContext = camelContext;
this.targetEndpoint = targetEndpoint;
}
@Override
public void configure() {
onException(TargetServerErrorException.class)
.maximumRedeliveries(2)
.redeliveryDelay(2500)
.retryAttemptedLogLevel(LoggingLevel.WARN)
.process(exchange -> {
// bellow equals 2
int redeliveryAttempts = exchange.getIn().getHeader(Exchange.REDELIVERY_COUNTER, Integer.class);
})
.stop();
from("direct:local-endpoint")
.marshal()
.json()
.to(targetEndpoint)
.choice()
.when(header(HTTP_RESPONSE_CODE).isEqualTo("500"))
.throwException(new TargetServerErrorException())
.endChoice()
.end();
}
public void callTarget(String objectId) {
camelContext.createProducerTemplate().sendBody("direct:local-endpoint", Map.of("objectId", objectId));
}
}
我想出了以下测试:
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class LocalEndpointTest {
private static final String MOCK_ENDPOINT = "mock:target-endpoint";
CamelContext camelContext;
MockEndpoint mockEndpoint;
LocalEndpoint localEndpoint;
@BeforeAll
void beforeAll() throws Exception {
camelContext = new DefaultCamelContext();
localEndpoint = new LocalEndpoint(camelContext, MOCK_ENDPOINT);
camelContext.addRoutes(localEndpoint);
camelContext.start();
mockEndpoint = camelContext.getEndpoint(MOCK_ENDPOINT, MockEndpoint.class);
}
@AfterAll
void afterAll() {
camelContext.stop();
}
@Test
void testCallTarget_serverError() throws InterruptedException {
// given
mockEndpoint.returnReplyHeader(Exchange.HTTP_RESPONSE_CODE, new ConstantExpression("500"));
mockEndpoint.expectedMessageCount(3); // gives: AssertionError: mock://target-endpoint Received message count. Expected: <3> but was: <1>
mockEndpoint.expectedHeaderReceived(Exchange.REDELIVERY_COUNTER, 2); // gives: AssertionError: mock://target-endpoint No header with name CamelRedeliveryCounter found for message: 0
// when
Throwable thrown = catchThrowable(() -> localEndpoint.callTarget("object-id"));
// then
mockEndpoint.assertIsSatisfied();
assertThat(thrown)
.cause().isInstanceOf(TargetServerErrorException.class)
.hasMessageContaining("received:", 500);
}
}
我预计会在消息计数断言中看到值 3,但令我惊讶的是它是 1。
我认为这个问题和
mockEndpoint
交换中缺少Camel标头可能与路由定义中分离的onException(Exception.class)
块和不同的上下文有关,但我不确定,因为我对Camel不够了解。
有没有办法在如此简单的测试中验证重新传递尝试? 或者至少有可能在
CamelRedeliveryCounter
内以某种方式获得 Camel 标头(如 mockEndpoint
)?
骆驼版本:4.3.0
编辑:
问题可能是由于:
默认情况下,Apache Camel 将从故障点开始执行任何重新交付(重试)尝试
我添加了
.errorHandler(noErrorHandler())
并重新定义了路线:
onException(TargetServerErrorException.class)
.maximumRedeliveries(2)
.redeliveryDelay(2500)
.retryAttemptedLogLevel(LoggingLevel.WARN)
.process(exchange -> {
int redeliveryAttempts = exchange.getIn().getHeader(Exchange.REDELIVERY_COUNTER, Integer.class); // equals 2
});
from("direct:local-endpoint")
.marshal()
.json()
.to("direct:retryable")
.end();
from("direct:retryable")
.errorHandler(noErrorHandler())
.to(targetEndpoint)
.choice()
.when(header(HTTP_RESPONSE_CODE).isEqualTo("500"))
.throwException(new TargetServerErrorException())
.endChoice()
但它仍然不起作用 - 我得到:
java.lang.AssertionError: mock://target-endpoint Received message count. Expected: <3> but was: <1>
事实证明,FAQ中已经提到的解决方案确实工作正常,并且正是我正在寻找的。我在测试中也有一些垃圾,清理它们后,添加
mockEndpoint.reset()
一切都开始成功通过。