【问题标题】:NotifyBuilder behaves inconsistently on repetitive runsNotifyBuilder 在重复运行时表现不一致
【发布时间】:2019-03-07 19:22:53
【问题描述】:

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

稍微调试一下 Camel 代码后,我注意到 org.apache.camel.builder.NotifyBuilder.EventPredicateSupport#onExchangeCompletedorg.apache.camel.builder.NotifyBuilder.EventPredicateSupport#onExchange 方法由于某些原因没有被调用,即使相应的事件已被触发。

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

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

有谁知道这种行为的原因是什么?

提前致谢。

这是我的测试类代码和骆驼配置:

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 -->

【问题讨论】:

  • 您是否尝试过将谓词的顺序更新为.from("activemq:fromQueueName").whenCompleted(1)

标签: java apache-camel activemq


【解决方案1】:

我遇到了同样的问题,问题是每次测试后骆驼上下文没有正确重置。该问题可以使用 Springboot @DirtiesContext 注解解决。

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

通过放置

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

在测试类的顶部,每次测试运行后都会重置使用的上下文。这可确保您的骆驼上下文在运行多个测试时不会尝试使用旧路由,从而导致轮询循环。

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

【讨论】:

  • 能否请您稍微加强一下您的答案,例如您是如何使用它的以及您将此注释添加到的位置?这将使未来的读者更清楚如何解决类似问题。
  • 谢谢,这是一个非常好的答案:)。
猜你喜欢
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 2019-01-28
  • 2019-09-12
  • 1970-01-01
  • 2017-11-20
  • 2016-11-27
  • 1970-01-01
相关资源
最近更新 更多