当前位置: 首页 > 知识库问答 >
问题:

使用带有OnException定义的adviceWith进行Camel路由测试

顾正初
2023-03-14
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");
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");
    }
}

由于这个测试设置只是一个较大项目的一小部分,所以像这里这样做可能听起来很傻,但核心意图是在测试时修改redeliveryDelay,因为“强制”IOException不需要等待3分钟,因此,为了加快单元测试的速度,可以将redeliveryDelay减少到大约10毫秒。

为了实现这一点,my test-method执行以下操作:

@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();
        ...
    }
}

这里,测试只是替换了IOException的onException段,以首先将重传递延迟从3分钟减少到10毫秒,并在最后添加了一个模拟endpoint。但是,当我尝试运行单元测试时,我将得到以下异常:

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.

因此,任何关于修改onException块或单元测试的redeliveryDelay的提示都非常受欢迎。

@edit:我现在还尝试将onException声明移到路由定义(从(...))之上,这也是Camel异常示例中的首选情况。但是,在这样做时,所有测试(即使是工作的测试)都失败了,因为context.getRouteDefinition(“somequeueid”).adviceWith(context,new AdviceWithRouteBuilder(){...});上出现NullPointerException,因为显然再也找不到路由本身了。我怀疑这是IntelliJ的问题,因为两个类都在同一个项目中,因此对路由的修改应该对测试类可见。

使用中的Camel版本:2.13.0,IntelliJ IDEA 13.1.2

@edit2:由于某种原因,context.getRouteDefinitions(“somequeueid”)返回null,如果OnException元素是在from块之外定义的,而一般的路由可以通过context.getRouteDefinitions().get(0)获得-不过,声明OnException部分需要作为顶级元素添加的异常仍然存在。

共有1个答案

孟自强
2023-03-14

在使用Java DSL时,路由的id是使用.routeID()方法设置的,而不是像上面所编码的那样使用.id()。这可能有助于解决的担忧。

与其硬编码重试延迟,更好的方法是使用属性来配置延迟。请查看CamelSpringTestSupport类中有关方法UseOverridePropertiesWithPropertiesComponent()的文档。

编辑

import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.test.junit4.CamelTestSupport;

public class DummyTest extends CamelTestSupport{
    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder(){
            @Override
            public void configure() throws Exception {

                from("direct://start")
                    .routeId("myroute")
                    .onException(Exception.class)
                        .id("myException")
                        .continued(true)
                    .end()
                    .throwException(new Exception())
                    .to("mock:end");
            }
        };
    }

    @org.junit.Test
    public void doTest() throws Exception{
        context.getRouteDefinition("myroute").adviceWith(context, new AdviceWithRouteBuilder(){
            @Override
            public void configure() throws Exception {
                context.getRouteDefinition("myroute")
                    .onException(Exception.class).setBody(constant("adviceWith")).continued(true);
            }});
        context.start();
        template.sendBody("direct://start", "original");
        String bodyAtEndOfExchange = getMockEndpoint("mock:end")
                .getExchanges().get(0).getIn().getBody(String.class);
        assertEquals("adviceWith", bodyAtEndOfExchange);        
        context.stop();
    }

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }
}
 类似资料:
  • 我目前正试图用Apache Camel测试一条现有的路线,但我不确定我做得对不对,因为我不完全理解Camel背后的所有概念。 话虽如此,以下是我想做的,关于以下示例路线: 这里的要点就是获取一个ImportDocumentProcess,并创建一个依赖于前一个对象的ImportDocumentTraItem。ImportDocument过程是通过exchange进行的。 以下是处理器代码: 我已经

  • 我在做一些关于Camel-CXf集成的研究,对下面的场景感到困惑。 所以我实现了一个Restendpoint 实现如下 } 路线 将其路由到实现中。但是由于实现返回一个响应对象,我不知道如何绕过这个对象构建路由。 一旦调用进入实现,我如何执行其他路由并发送回响应?在这种情况下,实现返回一个自定义对象。 其他路由如何附加到 CXF 路由? 我的 CXF 实现是否应该始终返回无效类型?如我所见,要访问

  • 我一直试图使用2.12.1-snapshot中的RabbitMQComponent版本让camel进行路由。这样做,我可以很容易地消费,但在路由到另一个队列时会遇到ad问题。 在这篇文章中,我已经验证了指定的交换机是否配置了适当的路由密钥。我注意到,我能够大量消费,但不能生产到out.queue。 以下是对处理消息的RabbitMQProducer的唯一引用。 我花了很多时间研究了RabbitMQ

  • 在一条骆驼路线中,我有两个url调用,调用两个不同的应用程序。 两者都能够抛出。因此,如果URL1抛出我必须处理的异常并将交换体设置为“数据源1不可用”,并且如果URL2抛出相同的异常,我想显示不同的消息。 如何使用onException处理此问题

  • 我有没有温和的方式说骆驼应该跳过这个(没有“camelerrorhandlerhandle”属性删除)? 谢谢

  • 我正在尝试使用angular与主播合作,我已经做了我的研究,但没有成功,所以我正在联系你们。 我有 3 个组件 {导航栏组件, 红色组件, 蓝色组件} 导航栏组件有 2 个锚点。我希望当我单击其中一个时,它实际上会将我引导到正确的组件 导航栏组件.ts 红色. component.ts blue.component.ts app.component.html 应用程序模块