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

Reply via email to