This is an automated email from the ASF dual-hosted git repository.

apupier 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 d46d51c24550 CAMEL-25666: Stabilize ConsumeChildrenIT - replace fixed 
delay with Awaitility
d46d51c24550 is described below

commit d46d51c245506b866182d16184a76380b0e82df4
Author: AurĂ©lien Pupier <[email protected]>
AuthorDate: Thu Oct 15 15:00:26 2026 +0200

    CAMEL-25666: Stabilize ConsumeChildrenIT - replace fixed delay with
    Awaitility
    
    The test shouldAwaitCreationAndGetDataNotification fires 5 ZooKeeper
    mutations in sequence and expects the mock endpoint to receive exactly
    5 messages (1 NodeCreated + 4 NodeChildrenChanged).
    
    The consumer uses a single-threaded OperationsExecutor: after each
    ChildrenChangedOperation fires it must synchronously call getChildren()
    in getResult(), deliver the exchange to the processor, then re-enqueue
    a copy of itself via createCopy(), and finally call installWatch() on
    the new copy to re-register the ZooKeeper watcher before the next event
    can be captured.
    
    The original test relied on a 200 ms pre-delay in TestZookeeperClient
    (delay(200) fires before the ZooKeeper mutation, not after). On a slow
    or loaded machine this is not long enough for the consumer to finish
    processing + re-registering the watch before the next mutation fires,
    causing a ZooKeeper NodeChildrenChanged event to be silently dropped.
    The mock then receives 4 instead of 5 messages.
    
    Fix: use Awaitility after each mutation to wait until the mock has
    actually received the corresponding message before triggering the next
    one. This guarantees the watch is re-registered before the next event
    fires, making the sequencing deterministic regardless of machine speed.
    
    Also rename the ZooKeeper node from /grimm to /grimm-ConsumeChildrenIT
    to isolate this test from any other test that might share the same
    ZooKeeper server, consistent with the same fix already applied to
    ConsumeDataIT and the cluster integration tests.
    
    Co-authored-by: IBM Bob 2.2.1
    Signed-off-by: AurĂ©lien Pupier <[email protected]>
---
 .../zookeeper/integration/ConsumeChildrenIT.java   | 37 ++++++++++++++++++----
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/integration/ConsumeChildrenIT.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/integration/ConsumeChildrenIT.java
index 9160db40961d..46730fe2f5e8 100644
--- 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/integration/ConsumeChildrenIT.java
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/integration/ConsumeChildrenIT.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.zookeeper.integration;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Exchange;
@@ -29,6 +30,7 @@ import org.apache.camel.component.zookeeper.ZooKeeperMessage;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.data.Stat;
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -36,11 +38,13 @@ import static 
org.junit.jupiter.api.Assertions.assertNotSame;
 
 public class ConsumeChildrenIT extends ZooKeeperITSupport {
 
+    private static final String ZK_NODE = "/grimm-ConsumeChildrenIT";
+
     @Override
     protected RouteBuilder[] createRouteBuilders() {
         return new RouteBuilder[] { new RouteBuilder() {
             public void configure() {
-                
from("zookeeper://{{zookeeper.connection.string}}/grimm?repeat=true&listChildren=true")
+                from("zookeeper://{{zookeeper.connection.string}}" + ZK_NODE + 
"?repeat=true&listChildren=true")
                         .sort(body(), new 
NaturalSortComparator(Order.Descending))
                         .to("mock:zookeeper-data");
             }
@@ -52,19 +56,38 @@ public class ConsumeChildrenIT extends ZooKeeperITSupport {
         MockEndpoint mock = getMockEndpoint("mock:zookeeper-data");
         mock.expectedMessageCount(5);
 
-        client.createPersistent("/grimm", "parent");
-        client.create("/grimm/hansel", "child");
-        client.create("/grimm/gretel", "child");
-        client.delete("/grimm/hansel");
-        client.delete("/grimm/gretel");
+        client.createPersistent(ZK_NODE, "parent");
+        awaitMockReceivedCount(mock, 1);
+        client.create(ZK_NODE + "/hansel", "child");
+        awaitMockReceivedCount(mock, 2);
+        client.create(ZK_NODE + "/gretel", "child");
+        awaitMockReceivedCount(mock, 3);
+        client.delete(ZK_NODE + "/hansel");
+        awaitMockReceivedCount(mock, 4);
+        client.delete(ZK_NODE + "/gretel");
 
-        MockEndpoint.assertIsSatisfied(context);
+        MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
 
         validateExchangesContainListings(mock, createChildListing(), 
createChildListing("hansel"),
                 createChildListing("hansel", "gretel"), 
createChildListing("gretel"),
                 createChildListing());
     }
 
+    /**
+     * Waits until the mock has received at least {@code count} messages 
before the next ZooKeeper mutation is fired.
+     * <p>
+     * This ensures the previous ChildrenChangedOperation copy has been taken 
off the queue and its
+     * {@code installWatch()} called, which happens after the exchange is 
delivered to the mock. The tiny remaining gap
+     * between the mock receipt and the actual watch registration is covered 
by the 200 ms pre-delay inside
+     * {@link ZooKeeperITSupport.TestZookeeperClient#create} / {@code delete}. 
If that delay is ever removed, a short
+     * post-delay or a deeper hook into the consumer would be needed here to 
avoid reintroducing flakiness.
+     */
+    private void awaitMockReceivedCount(MockEndpoint mock, int count) {
+        Awaitility.await()
+                .atMost(10, TimeUnit.SECONDS)
+                .until(() -> mock.getReceivedCounter() >= count);
+    }
+
     private void validateExchangesContainListings(MockEndpoint mock, 
List<?>... expected)
             throws CamelExchangeException {
         int index = 0;

Reply via email to