Teste de rota de camelo usando conselhosCom definições de OnException
Eu tenho uma definição de rota Camel muito simples, que inclui apenas alguns predicados OnException para lidar com as respectivas exceções e algumas instruções de log.
from("hazelcast:seda:someQueue")
.id("someQueueID")
.onException(CustomException.class)
.handled(true)
.log(LoggingLevel.WARN, "custom exception noticed")
.end()
.onException(IOException.class, FileNotFoundException.class)
.asyncDelayedRedelivery()
.redeliveryDelay(3*1000*60) // 3 Minutes
.maximumRedeliveries(3)
.log(LoggingLevel.WARN, "io exception noticed")
.end()
.onException(Exception.class)
.log(LoggingLevel.WARN, "general exception noticed")
.end()
.log("Starting route")
.bean(TestBean.class)
.log("Finished route");
O bean em si também é simples, apenas verifica um parâmetro de cabeçalho e lança uma exceção apropriada
public class TestBean
{
@Handler
public void checkData(@Headers final Map<String, Object> headers)
throws CustomException, IOException, Exception
{
Integer testVal = (Integer)headers.get("TestValue");
if (0 == testVal)
throw new CustomException("CustomException");
else if (1 == testVal)
throw new IOException("IOException");
else
throw new Exception("Exception");
}
}
Como essa configuração de teste é apenas uma pequena parte de um projeto maior, pode parecer bobagem fazê-lo como apresentado aqui, mas o principal objetivo é modificar o redeliveryDelay no tempo de teste, pois uma IOException "forçada" não precisará esperar 3 minutos portanto, para acelerar um pouco os testes de unidade, o atraso na entrega pode ser reduzido para 10 ms.
Para conseguir isso, meu método de teste faz o seguinte:
@ContextConfiguration(classes = OnExceptionRouteTest.ContextConfig.class, loader = AnnotationConfigContextLoader.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class OnExceptionRouteTest extends CamelSpringTestSupport
{
@Override
protected AbstractApplicationContext createApplicationContext()
{
return new AnnotationConfigApplicationContext(ContextConfig.class)
}
@Configuration
public static class ContextConfig extends CamelConfiguration
{
@Override
protected void setupCamelContext(CamelContext camelContext) throws Exception
{
super.setupCamelContext(camelContext);
camelContext.addComponent("hazelcast", new StubComponent());
// some other unnecessary stuff
}
@Override
public List<RouteBuilder> routes()
{
final List<RouteBuilder> list = new ArrayList<>();
list.add(new OnExceptionRoute());
return list;
}
}
@Override
public boolean isUseAdviceWith()
{
return true;
}
@Test
public void testIOException()
{
context.getRouteDefinition("someQueueID")
.adviceWith(context, new AdviceWithRouteBuilder()
{
@Override
public void configure() throws Exception
{
this.weaveByType(OnExceptionDefinition.class)
.selectIndex(1)
.replace()
.onException(IOException.class, FileNotFound.class)
.asyncDelayedRedelivery()
.redeliveryDelay(10)
.maximumRedeliveries(3)
.log("modified io exception noticed")
.to("mock:ioError")
.end();
...
mockEndpoints();
}
});
context.start();
MockEndpoint ioErrorEndpoint = getMockEndpoint("mock:ioError");
...
ioErrorEndpoint.setExpectedMessageCount(1);
...
Map<String, Object> headers = new HashMap<>();
headers.put("TestValue", new Integer(1));
template.sendBodyAndHeaders("hazelcast:seda:someQueue", new Object(), headers);
...
ioErrorEndpoint.assertIsSatisfied();
...
}
}
Aqui, o teste substitui o segmento onException do IOException para reduzir primeiro o atraso da entrega de 3 minutos para 10 ms e adicionar um ponto final simulado no final. No entanto, quando tento executar o teste de unidade, receberei a seguinte exceção:
java.lang.IllegalArgumentException: The output must be added as top-level on the route. Try moving OnException[[class java.io.IOException, class java.io.FileNotFoundException] -> []] to the top of route.
No entanto, os exemplos nodocumentação oficial, tanto quanto eu os entendi corretamente, são muito semelhantes. Também tentei procurar a definição de exceção por meio de um predicado de ID definido e seu método correspondenteweaveById()
ou através doweaveByToString()
método, mas sem nenhum outro resultado. Eu também tentei remover a definição de exceção viaweaveByType(OnExceptionDefinition.class).selectIndex(1).remove();
e adicione a parte OnException viaweaveAddFirst().onException(...).async...;
mas com o mesmo resultado.
Anexar um ponto de extremidade de erro simulado, no entanto, é possível via f.e.weaveByToString("Log[io exception noticed]").after().to("mock:ioError");
Portanto, qualquer dica para modificar blocos onException ou redeliveryDelay para testes de unidade é bem-vinda.
@ Edit: Eu também tentei agora mover as declarações onException acima da definição de rota (from(...)
), como sugerido pela mensagem de exceção, e esse também foi o caso preferido no Camel'samostras de exceção. Ao fazer isso, no entanto, todos os testes (mesmo os que estão funcionando) falham a partir de umNullPointerException
emcontext.getRouteDefinition("someQueueID").adviceWith(context, new AdviceWithRouteBuilder() {... });
como obviamente a rota em si não pode mais ser encontrada. Duvido que esse seja um problema do IntelliJ, pois as duas classes estão dentro do mesmo projeto e, portanto, uma modificação da rota deve ser visível para a classe de teste.
Versão camel em uso: 2.13.0, IntelliJ IDEA 13.1.2
@ Edit2: Por alguma razãocontext.getRouteDefinitions("someQueueID")
retorna null se os elementos OnException forem definidos fora dofrom
bloco, enquanto a rota geral pode ser obtida viacontext.getRouteDefinitions().get(0)
- no entanto, a exceção informando que a parte OnException precisa ser adicionada como elemento de nível superior permanece.