Java NotifyBuilder在重复运行时的行为不一致

Java NotifyBuilder在重复运行时的行为不一致,java,apache-camel,activemq,Java,Apache Camel,Activemq,我想对我的应用程序进行端到端测试,我需要确保驼峰路线工作正常。我使用NotifyBuilder来确保消息已完成,并且由于使用消息需要一些时间,我希望让消息处理30秒(但如果消息完成得更快,则不应等待),然后继续验证。这很好,但是。。。但不幸的是,NotifyBuilder有时在消息完成时不会做出反应,但我的日志消息表明所有必需的步骤都已完成。这种情况并不总是发生,但有规律地发生,平均10次中有2次。有趣的是,我在几个测试中使用了这样的方法,但它们在这个问题上随机失败,通常是一次一个(所有其他测试

我想对我的应用程序进行端到端测试,我需要确保驼峰路线工作正常。我使用NotifyBuilder来确保消息已完成,并且由于使用消息需要一些时间,我希望让消息处理30秒(但如果消息完成得更快,则不应等待),然后继续验证。这很好,但是。。。但不幸的是,NotifyBuilder有时在消息完成时不会做出反应,但我的日志消息表明所有必需的步骤都已完成。这种情况并不总是发生,但有规律地发生,平均10次中有2次。有趣的是,我在几个测试中使用了这样的方法,但它们在这个问题上随机失败,通常是一次一个(所有其他测试都通过)

在调试Camel代码之后,我注意到由于某些原因,
org.apache.Camel.builder.NotifyBuilder.EventPredicateSupport#onExchange completed
org.apache.Camel.builder.NotifyBuilder.EventPredicateSupport#onExchange
方法不会被调用,即使触发了相应的事件

我还注意到,当单独运行测试(一次一个)时,一切都按预期进行。同样,当我两次发送一条相同的消息时,NotifyBuilder调用
org.apache.camel.builder.NotifyBuilder.EventPredicateSupport#OneExchangeCompleted
,仅针对第二条消息

我使用camel 2.18.3和jdk8u60。操作系统Linux Mint 17和CentOS(在Windows上似乎一切正常)。测试由命令行中的gradle任务在单个线程中执行

有人知道这种行为的原因是什么吗

提前谢谢

以下是我的测试类代码和camel配置:

public class EndToEndTest {

    @Resource(name = "camelContext")
    private CamelContext camelContext;
    @Produce(uri = "activemq:fromQueueName")
    private ProducerTemplate template;

    @Test
    public void testWithNotifyBuilder() {
        NotifyBuilder notify = new NotifyBuilder(camelContext)
            .whenCompleted(1)
            .from("activemq:fromQueueName")
            .create();
        template.sendBody("{\"json\":\"example\"}");
        assertTrue(notify.matches(30, TimeUnit.SECONDS));
        // other verifications
    }}

<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<!-- other endpoints and beans -->
<endpoint id="fromEndpoint" uri="activemq:fromQueueName"/>
<route>
    <from ref="fromEndpoint"/>
    <unmarshal>
        <custom ref="customMessageUnmarshaller"/>
    </unmarshal>
    <bean ref="customMessageConsumer"/>

    <onException redeliveryPolicyRef="defaultRedeliveryPolicy">
        <exception>java.net.SocketException</exception>
        <exception>javax.jms.JMSException</exception>
        <handled>
            <constant>true</constant>
        </handled>
    </onException>
</route>
<!-- other routes -->
公共类结束测试{
@资源(name=“camelContext”)
私人背景;
@生成(uri=“activemq:fromQueueName”)
私有产品模板;
@试验
公共void testWithNotifyBuilder(){
NotifyBuilder notify=新的NotifyBuilder(上下文)
.完成时(1)
.from(“activemq:fromQueueName”)
.create();
sendBody(“{\'json\':\'example\'”);
assertTrue(notify.matches(30,TimeUnit.SECONDS));
//其他核查
}}
java.net.SocketException
javax.jms.jmsceception
真的

我遇到了同样的问题,问题是骆驼上下文在每次测试后没有正确重置。可以使用Springboot注释修复此问题

我遇到的问题与此类似,不一致的测试通过了,而Jenkins中的构建由于随机测试失败而失败(即使它们在本地通过)。问题在于,在每个单元测试中使用的驼峰上下文并不总是在每次测试后重置。导致camel进入轮询循环,并在
NotifyBuilder.matchsMockWaitTime()超时时失败

通过放置

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
在测试类的顶部,在每次测试运行后都会重置所使用的上下文。这可以确保您的camel上下文在运行多个测试时不会尝试使用旧路由,从而导致轮询循环

@RunWith(CamelSpringBootRunner.class)
@SpringBootTest(classes = MyApplication.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class DeadChannelTest {

    @Autowired
    private CamelContext context;

    @Autowired
    private ProducerTemplate template;

    @Test
    public void testMoveFile() throws Exception {
        // use NotifyBuilder to wait for the file to be routed
        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();

        // create a new file in the inbox folder with the name hello.txt and containing Hello World as body
        template.sendBodyAndHeader("file://camel/route",
                FileUtils.readFileToString(new File(TestPath), "UTF-8"),
                Exchange.FILE_NAME,
                "testError.log");

        // notifier will wait for the file to be processed
        // and if that never happen it will time out after 10 seconds (default mock timeout)
        assertTrue(notify.matchesMockWaitTime());

        // test the file was moved
        File target = new File(ErrorFolder + "/testError.log");
        assertTrue("File should have been moved", target.exists());
    }

您是否尝试过将谓词的顺序更新为
.from(“activemq:fromQueueName”)。完成时(1)
?您是否可以稍微改进一下您的答案,例如您是如何使用它的,以及您将此注释添加到了何处?这将使未来的读者更清楚地了解如何解决类似问题。谢谢,这是一个非常好的答案:)。