Ani
Ani

Reputation: 91

Camel JUnit-Tests: wrong results with parallel execution

I use camel.version 2.18.1 and spring-boot 1.5.1.RELEASE.
I have some more or less complex Camel routes, where messages from MQ Topics will be consumed, filtered, transformed and finally routed to different MQ Topics.

from("{{sourceEP}}").to("{{archiveEP}}")
   .process(new MyProcessor())
   .to("{{archiveEP}}").to("{{resultEP}}");

application.properties

sourceEP=jms:topic:SOURCE
archiveEP=jms:topic:ARCHIVE
resultEP=jms:topic:TARGET

For each route there exists more then 40 different scenarios. Therefore I have nearly 50 JUnit-Tests for each route, in total I have nearly 400 JUnit-Tests which I run with the maven-surefire-plugin to achieve parallel test execution.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.19.1</version>
  <configuration>
    <parallel>classes</parallel>
    <threadCount>4</threadCount>
  </configuration>
</plugin>

The problem is when the JUnit-Tests run in parallel, this will result in inconsistences in the producer endpoints (EDIT: for testing I use the Mock endpoints from Camel). The parallel tests affected the other tests and the expected number of messages in the target endpoints are incorrect.

Test: application.properties

sourceEP=direct:start
archiveEP=mock:archive
resultEP=mock:result

RouteTest.java

@RunWith(CamelSpringBootRunner.class)
@SpringBootTest(classes = MyApplication.class)
public class RouteTest {
    @Autowired
    private CamelContext context;

    @EndpointInject(uri = "{{archiveEP}}")
    protected MockEndpoint archiveEndpoint;

    @EndpointInject(uri = "{{resultEP}}")
    protected MockEndpoint resultEndpoint;

    @Produce(uri = "{{sourceEP}}")
    protected ProducerTemplate sourceEndpoint;

    @Before
    public void setup() {
        sourceEndpoint.cleanUp();
        archiveEndpoint.reset();
        resultEndpoint.reset();
    }

    @Test
    public void test1() throws Exception {
        sourceEndpoint.sendBody("some text");

        archiveEndpoint.expectedMessageCount(2);
        archiveEndpoint.assertIsSatisfied();

        resultEndpoint.expectedMessageCount(1);
        resultEndpoint.assertIsSatisfied();

        resultEndpoint.expectedBodiesReceived("expected output");
    }

    @Test
    public void test2() throws Exception {
        sourceEndpoint.sendBody("another text");

        archiveEndpoint.expectedMessageCount(2);
        archiveEndpoint.assertIsSatisfied();

        resultEndpoint.expectedMessageCount(1);
        resultEndpoint.assertIsSatisfied();

        resultEndpoint.expectedBodiesReceived("another output");
    }

    ...
} 

My question, is it possible at all to run the JUnit-Tests of Camel routes in parallel?

I tried to add @DirtiesContext on the test methods to force Spring Testing to automatically reload the CamelContext after each test method: http://camel.apache.org/testing.html
Which of course is not working at parallel test execution, because the result is still random and the expected number of messages is incorrect.

I ended up to set these tests which will test the Camel routes to @NotThreadSafe to enforce a single thread execution. Only these JUnit-Tests which will test other functionality than the Camel routing are executed in parallel.

But this is not a satisfied solution concerning the amount of nearly 400 JUnit-Tests.
Isn't there any configuration or setting to test Camel routes in parallel which will work correct?

Upvotes: 3

Views: 1048

Answers (1)

burki
burki

Reputation: 7005

Your MQ Topics are stateful and therefore "not threadsafe". As soon as multiple tests run in parallel, the number of messages in the topics is not foreseeable.

To solve this problem you have to isolate the stateful part of your tests, i.e. your MQ Topics. You would have to generate unique MQ topic names per test, so that each test has its own MQ topics. If this is the case, the message size is well defined as in a single-thread execution.

Or as an in-topic-isolation alternative, you could use JMS message selectors to isolate the messages in a topic for the different tests. In this case each test must set a message header with a unique value and consumes only messages with this value.

Upvotes: 1

Related Questions