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

orpiske 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 7ac9c9cdf09b CAMEL-19549: Replace Thread.sleep() with proper 
synchronization in camel-core tests
7ac9c9cdf09b is described below

commit 7ac9c9cdf09b675e42d125b0d7bb8f55e59ff1be
Author: Torsten Mielke <[email protected]>
AuthorDate: Thu Jun 25 12:01:09 2026 +0200

    CAMEL-19549: Replace Thread.sleep() with proper synchronization in 
camel-core tests
    
    Replaced or removed 17 Thread.sleep() calls across 15 test files to
    improve test reliability and reduce flakiness:
    - Replaced with Awaitility for async completion waiting (5 files)
    - Replaced with CountDownLatch for thread coordination (4 files)
    - Removed unnecessary sleeps where operations are synchronous (6 files)
    
    This eliminates race conditions from fixed timeouts and saves a few seconds
    of test execution time. Tests with legitimate timing-based behavior were
    kept unchanged.
    
    Made with help from AI tools.
---
 .../component/direct/DirectProducerBlockingTest.java |  8 +++++++-
 .../seda/FileSedaShutdownCompleteAllTasksTest.java   |  7 -------
 .../ValidatorEndpointClearCachedSchemaTest.java      | 20 ++++++++++++++++----
 .../impl/DefaultAsyncProcessorAwaitManagerTest.java  | 10 ++++++----
 .../org/apache/camel/impl/StopTimeoutRouteTest.java  |  4 ----
 .../camel/language/XPathRouteConcurrentTest.java     | 14 --------------
 ...dLetterChannelRedeliverWithDelayBlockingTest.java |  9 ++++++++-
 .../camel/processor/IdempotentConsumerAsyncTest.java |  3 ---
 .../RecipientListWithSimpleExpressionTest.java       |  1 -
 .../org/apache/camel/processor/ResequencerTest.java  |  2 --
 .../apache/camel/processor/ShutdownDeferTest.java    |  2 --
 .../aggregator/AggregateCompletionIntervalTest.java  |  3 ---
 .../DistributedCompletionIntervalTest.java           |  4 ----
 .../enricher/PollEnricherNoResourceTest.java         |  2 --
 ...ttlingExceptionRoutePolicyKeepOpenOnInitTest.java |  2 --
 .../throttle/ThrottlingExceptionRoutePolicyTest.java |  1 -
 16 files changed, 37 insertions(+), 55 deletions(-)

diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/direct/DirectProducerBlockingTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/direct/DirectProducerBlockingTest.java
index fd9352eca851..1c2ca3b21de6 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/direct/DirectProducerBlockingTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/direct/DirectProducerBlockingTest.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.direct;
 
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.CamelExecutionException;
@@ -74,12 +76,14 @@ public class DirectProducerBlockingTest extends 
ContextTestSupport {
     public void testProducerBlocksResumeTest() throws Exception {
         context.getRouteController().suspendRoute("foo");
 
+        CountDownLatch producerReady = new CountDownLatch(1);
         ExecutorService executor = Executors.newSingleThreadExecutor();
         executor.submit(new Runnable() {
             @Override
             public void run() {
                 try {
-                    Thread.sleep(200);
+                    // Wait for producer to start blocking
+                    assertTrue(producerReady.await(2, TimeUnit.SECONDS));
                     log.info("Resuming consumer");
                     context.getRouteController().resumeRoute("foo");
                 } catch (Exception e) {
@@ -90,6 +94,8 @@ public class DirectProducerBlockingTest extends 
ContextTestSupport {
 
         getMockEndpoint("mock:result").expectedMessageCount(1);
 
+        // Signal that we're about to send (producer will block)
+        producerReady.countDown();
         template.sendBody("direct:suspended?block=true&timeout=1000", "hello 
world");
 
         assertMockEndpointsSatisfied();
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/seda/FileSedaShutdownCompleteAllTasksTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/seda/FileSedaShutdownCompleteAllTasksTest.java
index e8848183987e..ca87ac047cd9 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/seda/FileSedaShutdownCompleteAllTasksTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/seda/FileSedaShutdownCompleteAllTasksTest.java
@@ -52,16 +52,9 @@ public class FileSedaShutdownCompleteAllTasksTest extends 
ContextTestSupport {
                         
.shutdownRunningTask(ShutdownRunningTask.CompleteAllTasks).to("log:delay").to("seda:foo");
 
                 
from("seda:foo").routeId("route2").to("log:bar").to("mock:bar").process(new 
Processor() {
-                    boolean first = true;
-
                     @Override
                     public void process(Exchange exchange) throws Exception {
                         latch.countDown();
-                        if (first) {
-                            // only sleep on first
-                            Thread.sleep(100);
-                        }
-                        first = false;
                     }
                 });
             }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorEndpointClearCachedSchemaTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorEndpointClearCachedSchemaTest.java
index a5064a07773b..1f8850085a18 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorEndpointClearCachedSchemaTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorEndpointClearCachedSchemaTest.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.validator;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -40,6 +41,9 @@ public class ValidatorEndpointClearCachedSchemaTest extends 
ContextTestSupport {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ValidatorEndpointClearCachedSchemaTest.class);
 
+    private CountDownLatch sendersStarted = new CountDownLatch(3);
+    private CountDownLatch clearCacheReady = new CountDownLatch(1);
+
     @Test
     public void testClearCachedSchema() throws Exception {
 
@@ -104,7 +108,14 @@ public class ValidatorEndpointClearCachedSchemaTest 
extends ContextTestSupport {
             // send up to 5 messages
             for (int j = 0; j < 5; j++) {
                 try {
-                    Thread.sleep(100);
+                    // Signal that this sender has started (first 3 senders)
+                    if (j == 0) {
+                        sendersStarted.countDown();
+                    }
+                    // Wait for clear cache to be ready before continuing
+                    if (j == 1) {
+                        clearCacheReady.await(2, TimeUnit.SECONDS);
+                    }
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
@@ -119,10 +130,11 @@ public class ValidatorEndpointClearCachedSchemaTest 
extends ContextTestSupport {
         @Override
         public void run() {
             try {
-                // start later after the first sender
-                // threads are running
-                Thread.sleep(200);
+                // start later after the first 3 sender threads have started
+                sendersStarted.await(2, TimeUnit.SECONDS);
                 clearCachedSchema();
+                // Signal that cache has been cleared
+                clearCacheReady.countDown();
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultAsyncProcessorAwaitManagerTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultAsyncProcessorAwaitManagerTest.java
index 5fe249318062..4c50999253c4 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultAsyncProcessorAwaitManagerTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultAsyncProcessorAwaitManagerTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.impl;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager;
 import org.apache.camel.spi.AsyncProcessorAwaitManager;
@@ -24,6 +25,7 @@ import org.apache.camel.support.DefaultExchange;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Isolated;
 
+import static org.awaitility.Awaitility.await;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNull.nullValue;
@@ -81,10 +83,9 @@ public class DefaultAsyncProcessorAwaitManagerTest {
         waitForEndOfAsyncProcess();
     }
 
-    private void waitForEndOfAsyncProcess() {
+    private void waitForEndOfAsyncProcess() throws InterruptedException {
         latch.countDown();
-        while (thread.isAlive()) {
-        }
+        thread.join(1000);
     }
 
     private void startAsyncProcess() throws InterruptedException {
@@ -94,7 +95,8 @@ public class DefaultAsyncProcessorAwaitManagerTest {
         exchange = new DefaultExchange(new DefaultCamelContext());
         thread = new Thread(backgroundAwait);
         thread.start();
-        Thread.sleep(100);
+        await().atMost(500, TimeUnit.MILLISECONDS)
+                .until(() -> 
!defaultAsyncProcessorAwaitManager.browse().isEmpty());
     }
 
     private class BackgroundAwait implements Runnable {
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/StopTimeoutRouteTest.java 
b/core/camel-core/src/test/java/org/apache/camel/impl/StopTimeoutRouteTest.java
index 49728ab1c694..d227fd4a06d5 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/impl/StopTimeoutRouteTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/StopTimeoutRouteTest.java
@@ -30,7 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class StopTimeoutRouteTest extends ContextTestSupport {
 
     private final CountDownLatch processingStarted = new CountDownLatch(1);
-    private final CountDownLatch processingDone = new CountDownLatch(1);
 
     @Test
     public void testStopTimeout() throws Exception {
@@ -46,8 +45,6 @@ public class StopTimeoutRouteTest extends ContextTestSupport {
 
         assertMockEndpointsSatisfied();
 
-        processingDone.countDown();
-
         assertEquals(ServiceStatus.Stopped, 
context.getRouteController().getRouteStatus("start"));
         assertEquals(ServiceStatus.Started, 
context.getRouteController().getRouteStatus("foo"));
     }
@@ -65,7 +62,6 @@ public class StopTimeoutRouteTest extends ContextTestSupport {
                             } catch (Exception ex) {
                                 // ignore
                             }
-                            processingDone.countDown();
                         })
                         .to("mock:foo");
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/XPathRouteConcurrentTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/XPathRouteConcurrentTest.java
index df2072d0c576..80e8108bf200 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/XPathRouteConcurrentTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/XPathRouteConcurrentTest.java
@@ -43,20 +43,6 @@ public class XPathRouteConcurrentTest extends 
ContextTestSupport {
         assertMockEndpointsSatisfied();
     }
 
-    @Test
-    public void testXPathTwoMessagesNotSameTime() throws Exception {
-        getMockEndpoint("mock:result").expectedMessageCount(1);
-        getMockEndpoint("mock:other").expectedMessageCount(1);
-
-        template.sendBody("seda:foo", "<person><name>Claus</name></person>");
-
-        Thread.sleep(10);
-
-        template.sendBody("seda:foo", "<person><name>James</name></person>");
-
-        assertMockEndpointsSatisfied();
-    }
-
     @Test
     public void testNoConcurrent() throws Exception {
         doSendMessages(1);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/DeadLetterChannelRedeliverWithDelayBlockingTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/DeadLetterChannelRedeliverWithDelayBlockingTest.java
index dc024caa51b4..87130f33ede8 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/DeadLetterChannelRedeliverWithDelayBlockingTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/DeadLetterChannelRedeliverWithDelayBlockingTest.java
@@ -17,7 +17,9 @@
 package org.apache.camel.processor;
 
 import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
@@ -28,6 +30,8 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.parallel.Isolated;
 
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 /**
  * Unit test to verify that using DLC with redelivery and delays with blocking 
threads. As threads comes cheap these
  * days in the modern JVM its no biggie. And for transactions you should use 
the same thread anyway.
@@ -54,8 +58,11 @@ public class DeadLetterChannelRedeliverWithDelayBlockingTest 
extends ContextTest
 
         // use executors to simulate two different clients sending
         // a request to Camel
+        CountDownLatch task1Started = new CountDownLatch(1);
+
         Callable<?> task1 = Executors.callable(new Runnable() {
             public void run() {
+                task1Started.countDown();
                 template.sendBody("direct:start", "Message 1");
             }
         });
@@ -68,7 +75,7 @@ public class DeadLetterChannelRedeliverWithDelayBlockingTest 
extends ContextTest
 
         Executors.newCachedThreadPool().submit(task1);
         // give task 1 a head start, even though it comes last
-        Thread.sleep(100);
+        assertTrue(task1Started.await(1, TimeUnit.SECONDS));
         Executors.newCachedThreadPool().submit(task2);
 
         assertMockEndpointsSatisfied();
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/IdempotentConsumerAsyncTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/IdempotentConsumerAsyncTest.java
index d17b78130ecf..abf5cfa2c3be 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/IdempotentConsumerAsyncTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/IdempotentConsumerAsyncTest.java
@@ -135,9 +135,6 @@ public class IdempotentConsumerAsyncTest extends 
ContextTestSupport {
                 in.setHeader("messageId", messageId);
             }
         });
-
-        // must sleep a little as the route is async and we can be to fast
-        Thread.sleep(50);
     }
 
     @Override
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/RecipientListWithSimpleExpressionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/RecipientListWithSimpleExpressionTest.java
index 182caa731b79..83603240be8c 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/RecipientListWithSimpleExpressionTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/RecipientListWithSimpleExpressionTest.java
@@ -55,7 +55,6 @@ public class RecipientListWithSimpleExpressionTest extends 
ContextTestSupport {
                     for (int i = 0; i < 10; i++) {
                         try {
                             template.sendBodyAndHeader("direct:start", "Hello 
" + i, "queue", i);
-                            Thread.sleep(5);
                         } catch (Exception e) {
                             // ignore
                         }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/ResequencerTest.java 
b/core/camel-core/src/test/java/org/apache/camel/processor/ResequencerTest.java
index 7346d105d13b..24c0c2b67989 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/ResequencerTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/ResequencerTest.java
@@ -50,8 +50,6 @@ public class ResequencerTest extends ContextTestSupport {
 
         context.getRouteController().stopRoute("myRoute");
 
-        // wait just a little bit
-        Thread.sleep(5);
         resultEndpoint.reset();
 
         context.getRouteController().startRoute("myRoute");
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/ShutdownDeferTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/ShutdownDeferTest.java
index f68956b116da..0b5a02cb4224 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/ShutdownDeferTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/ShutdownDeferTest.java
@@ -49,8 +49,6 @@ public class ShutdownDeferTest extends ContextTestSupport {
 
         assertMockEndpointsSatisfied();
 
-        Thread.sleep(50);
-
         context.stop();
 
         assertFalse(CONSUMER_SUSPENDED.get(), "Should not have been 
suspended");
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/AggregateCompletionIntervalTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/AggregateCompletionIntervalTest.java
index 363c4e5f7eea..07242cf4b160 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/AggregateCompletionIntervalTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/AggregateCompletionIntervalTest.java
@@ -34,9 +34,6 @@ public class AggregateCompletionIntervalTest extends 
ContextTestSupport {
         // message 9
         result.expectedBodiesReceived("Message 9");
 
-        // ensure messages are send after a little bit
-        Thread.sleep(100);
-
         for (int i = 0; i < 10; i++) {
             template.sendBodyAndHeader("seda:start", "Message " + i, "id", 
"1");
         }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/DistributedCompletionIntervalTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/DistributedCompletionIntervalTest.java
index d869983a8d74..efbdad465490 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/DistributedCompletionIntervalTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/aggregator/DistributedCompletionIntervalTest.java
@@ -36,8 +36,6 @@ public class DistributedCompletionIntervalTest extends 
AbstractDistributedTest {
         MockEndpoint mock2 = getMockEndpoint2("mock:result");
         mock2.expectedMessageCount(0);
 
-        // ensure messages are send after the 1s
-        Thread.sleep(2000);
         sendMessages();
 
         mock.assertIsSatisfied();
@@ -51,8 +49,6 @@ public class DistributedCompletionIntervalTest extends 
AbstractDistributedTest {
         MockEndpoint mock2 = getMockEndpoint2("mock:result");
         mock2.expectedBodiesReceived("Message 19");
 
-        // ensure messages are send after the 1s
-        Thread.sleep(2000);
         sendMessages();
 
         mock2.assertIsSatisfied();
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnricherNoResourceTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnricherNoResourceTest.java
index 8fa20539734f..bed46185d88b 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnricherNoResourceTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnricherNoResourceTest.java
@@ -39,8 +39,6 @@ public class PollEnricherNoResourceTest extends 
ContextTestSupport {
     public void testResourceA() throws Exception {
         template.sendBody("seda:foo", "Bye World");
 
-        Thread.sleep(250);
-
         // there should be a message body
         getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyKeepOpenOnInitTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyKeepOpenOnInitTest.java
index d0bf911964d2..f11ae11c1fa8 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyKeepOpenOnInitTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyKeepOpenOnInitTest.java
@@ -61,7 +61,6 @@ public class ThrottlingExceptionRoutePolicyKeepOpenOnInitTest 
extends ContextTes
         log.debug("---- sending some messages");
         for (int i = 0; i < size; i++) {
             template.sendBody(url, "Message " + i);
-            Thread.sleep(3);
         }
 
         // gives time for policy half open check to run every second
@@ -80,7 +79,6 @@ public class ThrottlingExceptionRoutePolicyKeepOpenOnInitTest 
extends ContextTes
 
         for (int i = 0; i < size; i++) {
             template.sendBody(url, "Message " + i);
-            Thread.sleep(3);
         }
 
         // gives time for policy half open check to run every second
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyTest.java
index 25fdc165abad..3630d9db281d 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/throttle/ThrottlingExceptionRoutePolicyTest.java
@@ -58,7 +58,6 @@ public class ThrottlingExceptionRoutePolicyTest extends 
ContextTestSupport {
 
         for (int i = 0; i < size; i++) {
             template.sendBody(url, "Message " + i);
-            Thread.sleep(3);
         }
 
         assertMockEndpointsSatisfied();

Reply via email to