This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch fix-flaky-test-hazelcastreplicatedmapconsumertest in repository https://gitbox.apache.org/repos/asf/camel.git
commit 880b5990dc7cd35b64f87fa5a28353554a86e2db Author: Guillaume Nodet <[email protected]> AuthorDate: Fri Jul 10 14:21:13 2026 +0000 Fix flaky HazelcastReplicatedmapConsumerTest (18% failure rate) Root cause: map.clear() in @BeforeEach fires async REMOVED events that bleed between tests because the Hazelcast entry listener is still active. Additionally, testRemove() calls map.remove() immediately after put() without waiting for the ADDED event, creating a race condition. Fix: - Stop routes before clearing the map to deregister the entry listener, preventing stale REMOVED events from reaching mock endpoints - Restart routes after clearing and resetting mocks - In testRemove(), wait for the ADDED event before calling remove() - Replace redundant Awaitility-wrapped MockEndpoint assertion in testEvict() with the native latch-based timed assertion Validated with 100 consecutive runs (0 failures). Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../HazelcastReplicatedmapConsumerTest.java | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastReplicatedmapConsumerTest.java b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastReplicatedmapConsumerTest.java index e4e051ec0b24..a23991dd4742 100644 --- a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastReplicatedmapConsumerTest.java +++ b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastReplicatedmapConsumerTest.java @@ -23,6 +23,7 @@ import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.replicatedmap.ReplicatedMap; import org.apache.camel.CamelContext; +import org.apache.camel.Route; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.test.junit6.CamelTestSupport; @@ -56,9 +57,18 @@ public class HazelcastReplicatedmapConsumerTest extends CamelTestSupport { } @BeforeEach - public void resetState() { + public void resetState() throws Exception { + // Stop routes to deregister the Hazelcast entry listener before clearing + // the map. This prevents async REMOVED events from clear() from bleeding + // into the next test's mock expectations. + for (Route route : context.getRoutes()) { + context.getRouteController().stopRoute(route.getRouteId()); + } map.clear(); MockEndpoint.resetMocks(context); + for (Route route : context.getRoutes()) { + context.getRouteController().startRoute(route.getRouteId()); + } } @Override @@ -83,19 +93,26 @@ public class HazelcastReplicatedmapConsumerTest extends CamelTestSupport { * mail from talip (hazelcast) on 21.02.2011: MultiMap doesn't support eviction yet. We can and should add this feature. */ @Test - public void testEvict() { + public void testEvict() throws InterruptedException { MockEndpoint out = getMockEndpoint("mock:evicted"); out.expectedMessageCount(1); map.put("4711", "my-foo", 100, TimeUnit.MILLISECONDS); - Awaitility.await().atMost(30000, TimeUnit.MILLISECONDS).untilAsserted( - () -> MockEndpoint.assertIsSatisfied(context)); + MockEndpoint.assertIsSatisfied(context, 30000, TimeUnit.MILLISECONDS); } @Test public void testRemove() throws InterruptedException { MockEndpoint out = getMockEndpoint("mock:removed"); out.expectedMessageCount(1); + map.put("4711", "my-foo"); + + // Wait for the ADDED event to be fully processed before removing, + // otherwise the remove may execute before the async ADDED event is delivered. + MockEndpoint added = getMockEndpoint("mock:added"); + Awaitility.await().atMost(5, TimeUnit.SECONDS) + .until(() -> added.getReceivedCounter() >= 1); + map.remove("4711"); MockEndpoint.assertIsSatisfied(context, 5000, TimeUnit.MILLISECONDS); this.checkHeaders(out.getExchanges().get(0).getIn().getHeaders(), HazelcastConstants.REMOVED);
