This is an automated email from the ASF dual-hosted git repository.
gnodet 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 ab96e61c797c CAMEL-23887: Fix flaky SjmsConnectionRecoveryTest timing
issues (#24610)
ab96e61c797c is described below
commit ab96e61c797c552edafb85f10295ee041f7c5bac
Author: Guillaume Nodet <[email protected]>
AuthorDate: Sun Jul 12 08:33:49 2026 +0200
CAMEL-23887: Fix flaky SjmsConnectionRecoveryTest timing issues (#24610)
CAMEL-23887: Fix flaky SjmsConnectionRecoveryTest timing issues
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../component/sjms/SjmsConnectionRecoveryTest.java | 40 ++++++++++++----------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git
a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/SjmsConnectionRecoveryTest.java
b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/SjmsConnectionRecoveryTest.java
index d79dfd4b3191..cea5185d398a 100644
---
a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/SjmsConnectionRecoveryTest.java
+++
b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/SjmsConnectionRecoveryTest.java
@@ -133,7 +133,7 @@ public class SjmsConnectionRecoveryTest extends
CamelTestSupport {
// Phase 1: verify normal consumption (also confirms consumer is fully
started)
mock.expectedMessageCount(1);
template.sendBody(SJMS_QUEUE_NAME, "before-failure");
- mock.assertIsSatisfied();
+ MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
mock.reset();
// Phase 2: simulate a transient JMS connection exception.
@@ -145,29 +145,31 @@ public class SjmsConnectionRecoveryTest extends
CamelTestSupport {
ExceptionListener container = (ExceptionListener)
containerField.get(sjmsConsumer);
container.onException(new JMSException("Simulated transient connection
failure"));
- // Phase 3: wait for recovery to complete and for multiple recovery
intervals to pass.
- // With recoveryInterval=1000ms and BackgroundTask initial delay=1s:
- // t=0s: onException fires, consumers/sessions nullified, recovery
scheduled
- // t=1s: recovery iteration 1 — creates new connection + consumers
- // t=2s: BUG: iteration 2 — creates another connection, skips
consumer re-creation
- // t=3s: BUG: iteration 3 — creates yet another connection
- // By t=4s, if the bug is present, 3+ connections were created.
- await().pollDelay(4 * RECOVERY_INTERVAL_MS, TimeUnit.MILLISECONDS)
+ // Phase 3: wait for recovery to create a new connection.
+ // This uses a condition-based wait instead of a hardcoded sleep, so it
+ // adapts to CI environments where recovery may take longer.
+ await().atMost(30, TimeUnit.SECONDS)
+ .until(() -> countingFactory.createCount.get() >
connectionsBefore);
+
+ // Phase 4: verify recovery created exactly one connection and then
stopped.
+ // First confirm exactly one new connection was created.
+ int connectionsAfterRecovery = countingFactory.createCount.get();
+ assertEquals(connectionsBefore + 1, connectionsAfterRecovery,
+ "Recovery should create exactly one new connection");
+
+ // Then wait several recovery intervals to confirm no additional
connections
+ // are created — this catches the infinite-loop bug where recovery
keeps
+ // destroying and recreating connections.
+ await().pollDelay(3 * RECOVERY_INTERVAL_MS, TimeUnit.MILLISECONDS)
.atMost(5 * RECOVERY_INTERVAL_MS, TimeUnit.MILLISECONDS)
- .until(() -> true);
-
- // Phase 4: assert recovery happened exactly once and stopped.
- int connectionsAfter = countingFactory.createCount.get();
- int recoveryConnections = connectionsAfter - connectionsBefore;
- assertEquals(1, recoveryConnections,
- "Recovery should create exactly one new connection and stop, "
- + "but created " +
recoveryConnections
- + " — the recovery loop did not
stop after successful reconnection");
+ .untilAsserted(() -> assertEquals(connectionsAfterRecovery,
+ countingFactory.createCount.get(),
+ "Recovery loop should have stopped — connection count
should remain stable"));
// Phase 5: verify messages are consumed after recovery.
mock.expectedMessageCount(1);
template.sendBody(SJMS_QUEUE_NAME, "after-failure");
- mock.assertIsSatisfied();
+ MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
}
@Override