This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 6f6325683c90 CAMEL-21438: Fix flaky JMS consumer startup races in IBM
MQ and Artemis tests (#24390)
6f6325683c90 is described below
commit 6f6325683c90c11c83fef20039ffb7e184063322
Author: Adriano Machado <[email protected]>
AuthorDate: Fri Jul 3 16:34:58 2026 -0400
CAMEL-21438: Fix flaky JMS consumer startup races in IBM MQ and Artemis
tests (#24390)
* CAMEL-21438: Improve IBM MQ test infra readiness before JMS tests
Wait for the listener port and a successful JMS connection after the
container starts so tests do not race against a broker that is not yet
accepting clients.
Co-authored-by: Cursor <[email protected]>
* CAMEL-21438: Fix flaky JMS consumer startup races in tests
Add a shared waitForJmsConsumerRoutes helper with a 100ms route uptime
threshold and use it in IBM MQ and Artemis consumer tests that were
sending before listeners were ready.
Co-authored-by: Cursor <[email protected]>
* CAMEL-21438: Address review feedback on JMS test race fixes
- IBM MQ infra: combine the listener-port and log-message waits via
WaitAllStrategy (chained waitingFor() replaces, not combines). Use
WITH_INDIVIDUAL_TIMEOUTS_ONLY so each strategy keeps its own timeout
instead of the 30s outer cap the default mode imposes.
- AbstractJMSTest.waitForJmsConsumerRoutes: null-check the route so a
missing/removed id times out clearly instead of throwing NPE; reword
Javadoc to state uptime is a heuristic and document parameters.
- AbstractPersistentJMSTest: add a minUptimeMillis overload.
- SingleMessageSameTopicIT: restore the 200ms uptime threshold for topic
consumers via a named constant at all call sites.
- MultipleMessagesSameTopicIT: migrate the inline uptime waits to the
shared helper (200ms).
- JmsComponentIbmMQTest: wait only on the JMS consumer route and drop the
unused producer routeId.
Co-authored-by: Cursor <[email protected]>
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* CAMEL-21438: Address review feedback on JMS test helper placement
Extract the JMS consumer-route wait helpers into a standalone
JmsTestHelper so the same static API is reachable identically from all
three JMS test lineages (AbstractJMSTest, AbstractPersistentJMSTest and
plain CamelTestSupport tests), removing the dual static/instance-wrapper
surface. Migrate all call sites accordingly.
Replace the TestUtils.waitFor sleep-retry loop in the IBM MQ infra
service with Awaitility for consistency with the rest of the change and
clearer timeout diagnostics.
Co-authored-by: Claude Opus 4.8 <[email protected]>
* CAMEL-21438: Merge SingleMessageSameTopicIT @BeforeEach to fix ordering
JUnit Jupiter does not honor @Order on @BeforeEach lifecycle methods and
does not guarantee the execution order of multiple @BeforeEach methods in
a single class. The split waitForConnections()/prepare() setup could
therefore still send the message before the consumer routes were ready,
preserving the race the PR set out to fix. Consolidate both into a single
@BeforeEach so the wait always precedes the send.
Co-authored-by: Claude Opus 4.8 <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
---
.../camel/component/jms/JmsComponentIbmMQTest.java | 7 ++-
.../apache/camel/component/jms/JmsTestHelper.java | 72 ++++++++++++++++++++++
.../consumers/MultipleMessagesSameTopicIT.java | 8 ++-
.../consumers/SingleMessageSameTopicIT.java | 20 +++---
.../consumers/TwoConsumerOnSameQueueIT.java | 5 ++
.../component/jms/issues/JmsReplyToIbmMQTest.java | 6 +-
.../jms/issues/JmsReplyToLoopIssueTest.java | 11 ++--
.../jms/temp/TemporaryQueueRouteTest.java | 5 +-
test-infra/camel-test-infra-ibmmq/pom.xml | 6 ++
.../services/IbmMQLocalContainerInfraService.java | 34 +++++++++-
10 files changed, 154 insertions(+), 20 deletions(-)
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsComponentIbmMQTest.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsComponentIbmMQTest.java
index dca3c8acbb51..64249742852f 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsComponentIbmMQTest.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsComponentIbmMQTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.jms;
+import java.util.concurrent.TimeUnit;
+
import jakarta.jms.ConnectionFactory;
import org.apache.camel.CamelContext;
@@ -42,9 +44,11 @@ public class JmsComponentIbmMQTest extends CamelTestSupport {
resultEndpoint.message(0).header("cheese").isEqualTo(123);
resultEndpoint.message(0).body().isEqualTo("Hello there!");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "consumer");
+
template.sendBodyAndHeader("direct:start", "Hello world", "cheese",
123);
- MockEndpoint.assertIsSatisfied(context);
+ MockEndpoint.assertIsSatisfied(context, 20, TimeUnit.SECONDS);
}
@Override
@@ -56,6 +60,7 @@ public class JmsComponentIbmMQTest extends CamelTestSupport {
.to("jms:queue:DEV.QUEUE.1");
from("jms:queue:DEV.QUEUE.1")
+ .routeId("consumer")
.process(exchange -> exchange.getIn().setBody("Hello
there!"))
.to("mock:result");
}
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsTestHelper.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsTestHelper.java
new file mode 100644
index 000000000000..f178d9db1754
--- /dev/null
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsTestHelper.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.jms;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Route;
+import org.awaitility.Awaitility;
+
+/**
+ * Shared helpers for JMS tests. Kept as a standalone utility so the same
static API is reachable from every JMS test
+ * lineage ({@link AbstractJMSTest}, {@link AbstractPersistentJMSTest} and
plain {@code CamelTestSupport} tests) without
+ * forcing them into a common base class.
+ */
+public final class JmsTestHelper {
+
+ public static final long JMS_CONSUMER_ROUTE_UPTIME_MILLIS = 100;
+ public static final long JMS_CONSUMER_ROUTE_WAIT_AT_MOST_MILLIS = 30_000;
+
+ private JmsTestHelper() {
+ }
+
+ /**
+ * Wait until the given routes have been running for {@link
#JMS_CONSUMER_ROUTE_UPTIME_MILLIS} milliseconds. Route
+ * uptime is only a heuristic for JMS listener registration on the broker:
once a consumer route has been up for a
+ * short while its listener is expected to be subscribed, so tests can
send without racing an unregistered listener.
+ *
+ * @param context the Camel context owning the routes
+ * @param routeIds the ids of the consumer routes to wait for
+ */
+ public static void waitForJmsConsumerRoutes(CamelContext context,
String... routeIds) {
+ waitForJmsConsumerRoutes(context, JMS_CONSUMER_ROUTE_UPTIME_MILLIS,
routeIds);
+ }
+
+ /**
+ * Wait until the given routes have been running for at least {@code
minUptimeMillis} milliseconds, giving up after
+ * {@link #JMS_CONSUMER_ROUTE_WAIT_AT_MOST_MILLIS} milliseconds. A missing
route (unknown id, or one already removed
+ * from the context) is treated as not-yet-ready rather than throwing, so
a misconfigured route id surfaces as a
+ * clear timeout instead of a {@link NullPointerException}.
+ *
+ * @param context the Camel context owning the routes
+ * @param minUptimeMillis the minimum route uptime, in milliseconds,
before a route is considered ready
+ * @param routeIds the ids of the consumer routes to wait for
+ */
+ public static void waitForJmsConsumerRoutes(CamelContext context, long
minUptimeMillis, String... routeIds) {
+ Awaitility.await().atMost(JMS_CONSUMER_ROUTE_WAIT_AT_MOST_MILLIS,
TimeUnit.MILLISECONDS).until(() -> {
+ for (String routeId : routeIds) {
+ Route route = context.getRoute(routeId);
+ if (route == null || route.getUptimeMillis() <=
minUptimeMillis) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+}
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/MultipleMessagesSameTopicIT.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/MultipleMessagesSameTopicIT.java
index 2ff59fe3de79..8b88ef431a24 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/MultipleMessagesSameTopicIT.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/MultipleMessagesSameTopicIT.java
@@ -19,8 +19,8 @@ package org.apache.camel.component.jms.integration.consumers;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jms.AbstractPersistentJMSTest;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.component.mock.MockEndpoint;
-import org.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -29,6 +29,9 @@ import org.junit.jupiter.api.Test;
*/
public class MultipleMessagesSameTopicIT extends AbstractPersistentJMSTest {
+ // topic subscriptions take a little longer to register than queue
consumers, so keep the longer 200ms threshold
+ private static final long TOPIC_ROUTE_UPTIME_MILLIS = 200;
+
@Test
public void testMultipleMessagesOnSameTopic() throws Exception {
getMockEndpoint("mock:a").expectedBodiesReceived("Hello Camel 1",
"Hello Camel 2", "Hello Camel 3",
@@ -46,8 +49,7 @@ public class MultipleMessagesSameTopicIT extends
AbstractPersistentJMSTest {
@BeforeEach
void waitForConnections() {
- Awaitility.await().until(() -> context.getRoute("a").getUptimeMillis()
> 200);
- Awaitility.await().until(() -> context.getRoute("b").getUptimeMillis()
> 200);
+ JmsTestHelper.waitForJmsConsumerRoutes(context,
TOPIC_ROUTE_UPTIME_MILLIS, "a", "b");
}
@Override
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/SingleMessageSameTopicIT.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/SingleMessageSameTopicIT.java
index d7cfc3468bcc..72056ac3eb51 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/SingleMessageSameTopicIT.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/SingleMessageSameTopicIT.java
@@ -18,8 +18,8 @@ package org.apache.camel.component.jms.integration.consumers;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jms.AbstractPersistentJMSTest;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.component.mock.MockEndpoint;
-import org.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@@ -31,8 +31,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SingleMessageSameTopicIT extends AbstractPersistentJMSTest {
+ // topic subscriptions take a little longer to register than queue
consumers, so keep the longer 200ms threshold
+ private static final long TOPIC_ROUTE_UPTIME_MILLIS = 200;
+
@BeforeEach
- void prepare() {
+ void waitAndPrepare() {
+ // JUnit does not honor @Order on @BeforeEach methods, so the wait and
the send must live in a single
+ // @BeforeEach to guarantee the consumer routes are ready before the
message is published.
+ JmsTestHelper.waitForJmsConsumerRoutes(context,
TOPIC_ROUTE_UPTIME_MILLIS, "a", "b");
+
getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
getMockEndpoint("mock:b").expectedBodiesReceived("Hello World");
@@ -59,6 +66,7 @@ public class SingleMessageSameTopicIT extends
AbstractPersistentJMSTest {
getMockEndpoint("mock:a").expectedMessageCount(0);
getMockEndpoint("mock:b").expectedBodiesReceived("Bye World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context,
TOPIC_ROUTE_UPTIME_MILLIS, "b");
template.sendBody("activemq:topic:SingleMessageSameTopicIT", "Bye
World");
MockEndpoint.assertIsSatisfied(context);
@@ -72,6 +80,7 @@ public class SingleMessageSameTopicIT extends
AbstractPersistentJMSTest {
getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
getMockEndpoint("mock:b").expectedBodiesReceived("Hello World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context,
TOPIC_ROUTE_UPTIME_MILLIS, "a", "b");
template.sendBody("activemq:topic:SingleMessageSameTopicIT", "Hello
World");
}
@@ -90,17 +99,12 @@ public class SingleMessageSameTopicIT extends
AbstractPersistentJMSTest {
getMockEndpoint("mock:a").expectedMessageCount(0);
getMockEndpoint("mock:b").expectedBodiesReceived("Bye World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context,
TOPIC_ROUTE_UPTIME_MILLIS, "b");
template.sendBody("activemq:topic:SingleMessageSameTopicIT", "Bye
World");
MockEndpoint.assertIsSatisfied(context);
}
- @BeforeEach
- void waitForConnections() {
- Awaitility.await().until(() -> context.getRoute("a").getUptimeMillis()
> 200);
- Awaitility.await().until(() -> context.getRoute("b").getUptimeMillis()
> 200);
- }
-
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/TwoConsumerOnSameQueueIT.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/TwoConsumerOnSameQueueIT.java
index 9e62f8202fee..71c185abbbc5 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/TwoConsumerOnSameQueueIT.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/integration/consumers/TwoConsumerOnSameQueueIT.java
@@ -23,6 +23,7 @@ import jakarta.jms.ConnectionFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.infra.artemis.common.ConnectionFactoryHelper;
import org.apache.camel.test.infra.artemis.services.ArtemisService;
@@ -80,6 +81,7 @@ public class TwoConsumerOnSameQueueIT extends
CamelTestSupport {
getMockEndpoint("mock:a").expectedMessageCount(0);
getMockEndpoint("mock:b").expectedBodiesReceived("Bye World", "Bye
World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "b");
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Bye
World");
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Bye
World");
@@ -108,6 +110,7 @@ public class TwoConsumerOnSameQueueIT extends
CamelTestSupport {
getMockEndpoint("mock:a").expectedMessageCount(0);
getMockEndpoint("mock:b").expectedBodiesReceived("Bye World", "Bye
World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "b");
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Bye
World");
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Bye
World");
@@ -118,6 +121,8 @@ public class TwoConsumerOnSameQueueIT extends
CamelTestSupport {
final MockEndpoint mockB = getMockEndpoint("mock:b");
final MockEndpoint mockA = getMockEndpoint("mock:a");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "a", "b");
+
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Hello
World");
template.sendBody("activemq:queue:TwoConsumerOnSameQueueTest", "Hello
World");
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToIbmMQTest.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToIbmMQTest.java
index 18bfa06b1358..d57e95c2f5b9 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToIbmMQTest.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToIbmMQTest.java
@@ -20,6 +20,7 @@ import jakarta.jms.ConnectionFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.test.infra.ibmmq.common.ConnectionFactoryHelper;
import org.apache.camel.test.infra.ibmmq.services.IbmMQService;
import org.apache.camel.test.infra.ibmmq.services.IbmMQServiceFactory;
@@ -37,10 +38,12 @@ public class JmsReplyToIbmMQTest extends CamelTestSupport {
@Test
public void testCustomJMSReplyToInOut() {
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "request");
+
template.sendBody("jms:queue:DEV.QUEUE.1", "What is your name?");
String reply
- = consumer.receiveBody("jms:queue:DEV.QUEUE.2", 5000,
String.class);
+ = consumer.receiveBody("jms:queue:DEV.QUEUE.2", 20000,
String.class);
assertEquals("My name is Camel", reply);
}
@@ -50,6 +53,7 @@ public class JmsReplyToIbmMQTest extends CamelTestSupport {
@Override
public void configure() {
from("jms:queue:DEV.QUEUE.1?replyTo=queue:DEV.QUEUE.2")
+ .routeId("request")
.to("log:hello")
.transform(constant("My name is Camel"));
}
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToLoopIssueTest.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToLoopIssueTest.java
index 0967f5a91fb5..6880056322bc 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToLoopIssueTest.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/issues/JmsReplyToLoopIssueTest.java
@@ -23,6 +23,7 @@ import org.apache.camel.ConsumerTemplate;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jms.AbstractJMSTest;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.infra.core.CamelContextExtension;
import org.apache.camel.test.infra.core.DefaultCamelContextExtension;
@@ -44,14 +45,16 @@ public class JmsReplyToLoopIssueTest extends
AbstractJMSTest {
protected ConsumerTemplate consumer;
@Test
- public void testReplyToLoopIssue() {
+ public void testReplyToLoopIssue() throws Exception {
getMockEndpoint("mock:foo").expectedBodiesReceived("World");
getMockEndpoint("mock:bar").expectedBodiesReceived("Bye World");
getMockEndpoint("mock:done").expectedBodiesReceived("World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "foo", "bar");
+
template.sendBodyAndHeader("direct:start", "World", "JMSReplyTo",
"queue:JmsReplyToLoopIssueTest.bar");
- // sleep a little to ensure we do not do endless loop
+ // fail fast if an endless reply loop keeps producing messages
Awaitility.await().atMost(250, TimeUnit.MILLISECONDS).untilAsserted(()
-> MockEndpoint.assertIsSatisfied(context));
}
@@ -70,11 +73,11 @@ public class JmsReplyToLoopIssueTest extends
AbstractJMSTest {
.to("activemq:queue:JmsReplyToLoopIssueTest.foo?preserveMessageQos=true")
.to("mock:done");
- from("activemq:queue:JmsReplyToLoopIssueTest.foo")
+
from("activemq:queue:JmsReplyToLoopIssueTest.foo").routeId("foo")
.to("log:foo?showAll=true", "mock:foo")
.transform(body().prepend("Bye "));
- from("activemq:queue:JmsReplyToLoopIssueTest.bar")
+
from("activemq:queue:JmsReplyToLoopIssueTest.bar").routeId("bar")
.to("log:bar?showAll=true", "mock:bar");
}
};
diff --git
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/temp/TemporaryQueueRouteTest.java
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/temp/TemporaryQueueRouteTest.java
index b9ac5418c466..c546bd78bc56 100644
---
a/components/camel-jms/src/test/java/org/apache/camel/component/jms/temp/TemporaryQueueRouteTest.java
+++
b/components/camel-jms/src/test/java/org/apache/camel/component/jms/temp/TemporaryQueueRouteTest.java
@@ -21,6 +21,7 @@ import org.apache.camel.ConsumerTemplate;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jms.AbstractJMSTest;
+import org.apache.camel.component.jms.JmsTestHelper;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.infra.core.CamelContextExtension;
import org.apache.camel.test.infra.core.TransientCamelContextExtension;
@@ -43,6 +44,8 @@ public class TemporaryQueueRouteTest extends AbstractJMSTest {
MockEndpoint endpoint = getMockEndpoint("mock:result");
endpoint.expectedBodiesReceived("Hello World");
+ JmsTestHelper.waitForJmsConsumerRoutes(context, "consumer");
+
template.sendBody(endpointUri, "Hello World");
endpoint.assertIsSatisfied();
@@ -57,7 +60,7 @@ public class TemporaryQueueRouteTest extends AbstractJMSTest {
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
- from(endpointUri).to("mock:result");
+ from(endpointUri).routeId("consumer").to("mock:result");
}
};
}
diff --git a/test-infra/camel-test-infra-ibmmq/pom.xml
b/test-infra/camel-test-infra-ibmmq/pom.xml
index b3811674cf50..55b7f4727f32 100644
--- a/test-infra/camel-test-infra-ibmmq/pom.xml
+++ b/test-infra/camel-test-infra-ibmmq/pom.xml
@@ -46,6 +46,12 @@
<artifactId>com.ibm.mq.jakarta.client</artifactId>
<version>${com-ibm-mq-jakarta-client-version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <version>${awaitility-version}</version>
+ </dependency>
</dependencies>
</project>
diff --git
a/test-infra/camel-test-infra-ibmmq/src/main/java/org/apache/camel/test/infra/ibmmq/services/IbmMQLocalContainerInfraService.java
b/test-infra/camel-test-infra-ibmmq/src/main/java/org/apache/camel/test/infra/ibmmq/services/IbmMQLocalContainerInfraService.java
index ccc9cd313463..00d32805b8a9 100644
---
a/test-infra/camel-test-infra-ibmmq/src/main/java/org/apache/camel/test/infra/ibmmq/services/IbmMQLocalContainerInfraService.java
+++
b/test-infra/camel-test-infra-ibmmq/src/main/java/org/apache/camel/test/infra/ibmmq/services/IbmMQLocalContainerInfraService.java
@@ -16,16 +16,25 @@
*/
package org.apache.camel.test.infra.ibmmq.services;
+import java.util.concurrent.TimeUnit;
+
+import jakarta.jms.Connection;
+import jakarta.jms.ConnectionFactory;
+import jakarta.jms.JMSException;
+
import org.apache.camel.spi.annotations.InfraService;
import org.apache.camel.test.infra.common.LocalPropertyResolver;
import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
import org.apache.camel.test.infra.common.services.ContainerService;
+import org.apache.camel.test.infra.ibmmq.common.ConnectionFactoryHelper;
import org.apache.camel.test.infra.ibmmq.common.IbmMQProperties;
+import org.awaitility.Awaitility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.containers.wait.strategy.WaitAllStrategy;
import org.testcontainers.utility.DockerImageName;
@InfraService(service = IbmMQInfraService.class,
@@ -61,8 +70,13 @@ public class IbmMQLocalContainerInfraService implements
IbmMQInfraService, Conta
.withEnv("MQ_QMGR_NAME",
IbmMQProperties.DEFAULT_QMGR_NAME)
.withEnv("MQ_APP_PASSWORD",
IbmMQProperties.DEFAULT_APP_PASSWORD)
.withLogConsumer(new Slf4jLogConsumer(LOG))
- .waitingFor(Wait.forLogMessage(
- ".*Queued Publish/Subscribe Daemon started for
queue manager.*", 1));
+ // AND the listener-port and log-message checks; a
plain chained waitingFor() would replace,
+ // not combine, the strategies.
WITH_INDIVIDUAL_TIMEOUTS_ONLY keeps each strategy's own timeout
+ // instead of the 30s outer cap the default
WaitAllStrategy mode would impose.
+ .waitingFor(new
WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY)
+ .withStrategy(Wait.forListeningPort())
+ .withStrategy(Wait.forLogMessage(
+ ".*Queued Publish/Subscribe Daemon
started for queue manager.*", 1)));
ContainerEnvironmentUtil.configurePorts(this,
ContainerEnvironmentUtil.isFixedPort(IbmMQLocalContainerInfraService.class),
@@ -88,6 +102,22 @@ public class IbmMQLocalContainerInfraService implements
IbmMQInfraService, Conta
// also starts admin console on https://localhost:9443/ibmmq/console,
user: admin, password: passw0rd
container.start();
registerProperties();
+ waitForJmsConnection();
+ }
+
+ private void waitForJmsConnection() {
+ Awaitility.await("IBM MQ accepting JMS connections")
+ .atMost(30, TimeUnit.SECONDS)
+ .pollInterval(1, TimeUnit.SECONDS)
+ .ignoreExceptionsInstanceOf(JMSException.class)
+ .until(() -> {
+ ConnectionFactory connectionFactory =
ConnectionFactoryHelper.createConnectionFactory(
+ queueManager(), channel(), listenerPort());
+ try (Connection connection =
connectionFactory.createConnection()) {
+ connection.start();
+ }
+ return true;
+ });
}
@Override