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

davsclaus 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 859fcf113151 CAMEL-21438: Fix six flaky tests and missing aarch64 
image for TensorFlow Serving (#23927)
859fcf113151 is described below

commit 859fcf113151ca232807c38fa02c0b489e2466bd
Author: Adriano Machado <[email protected]>
AuthorDate: Fri Jun 12 07:40:47 2026 -0400

    CAMEL-21438: Fix six flaky tests and missing aarch64 image for TensorFlow 
Serving (#23927)
    
    * CAMEL-21438: Fix missing image for Tensorflow Serving test-infra 
container on aarch64
    
    * CAMEL-21438: Fix flaky SimpleLRUCacheTest: await eviction after 
concurrent puts
    
    callEvictionIfNeeded() runs after OperationContext releases its read lock,
    so the cache can still be oversized when the CountDownLatch fires. Replace
    immediate post-latch assertions with Awaitility.await().untilAsserted() to
    give in-flight evictions time to complete before checking size and counter.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    * CAMEL-21438: Fix flaky DefaultConsumerBridgeErrorHandlerContinuedTest
    
    With continued(true) and bridgeErrorHandler=true, the bridge creates
    a synthetic exchange, the onException route executes, and the exchange
    then continues through the main route body (including mock:result).
    The test incorrectly expected mock:result to receive 0 messages.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    * CAMEL-21438: Fix flaky FileSortBy tests: set mock expectations before 
addRoutes
    
    MockEndpoint.expectedBodiesReceived() must be called before routes start
    delivering messages. With initialDelay=0 the file consumer fires on a
    background thread as soon as addRoutes() returns; if messages arrive before
    expectedBodiesReceived() is called, expectedBodyValues is still null so
    performAssertions() never populates actualBodyValues, causing the order
    assertion to compare each expected body against null.
    
    Fix: move getMockEndpoint() + expectedBodiesReceived() before addRoutes()
    in all three FileSortBy test classes. Also remove the no-op context.start() 
calls that widened the race window.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    * CAMEL-21438: Fix flaky FileProducerCharsetUTFtoISOConvertBodyToTest
    
    Two remaining issues after two prior fixes:
    
    1. Race between @BeforeEach and the file consumer: writeTestData() runs
       after setUp() has already started the context and route. With
       initialDelay=0 the consumer polls every 10ms; a poll landing between
       Files.newOutputStream() (creates 0-byte file) and fos.close() picks up
       an empty file and produces 0-byte output, causing the size > 0
       assertion to never be satisfied.
       Fix: write to a .tmp file first, then atomically rename (POSIX rename
       syscall). The consumer's fileName filter ignores the .tmp file and only
       ever sees the fully-written target.
    
    2. @AfterEach used Files.delete() instead of Files.deleteIfExists(): if
       the test fails before the output file is created, cleanup also throws,
       masking the original failure with "cannot run due to an error cleaning
       up". Fix: switch to Files.deleteIfExists().
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    * CAMEL-21438: Fix flaky QueueProducerQoSTest: queue consumer and explicit 
mock timeout
    
    Two issues caused non-deterministic failures:
    
    1. The expiry route consumed from `sjms:topic:ExpiryQueue` but Artemis 
routes
       expired messages to an ANYCAST address. A JMS Topic consumer creates a
       MULTICAST subscription, which does not receive ANYCAST messages. Whether
       the test passed depended on which subscriber created the ExpiryQueue 
address
       first. Fixed by switching to `sjms:queue:ExpiryQueue`.
    
    2. Both test methods called the static 
`MockEndpoint.assertIsSatisfied(context)`
       which delegates to each mock's own `resultWaitTime` (defaults to 0). With
       `requestTimeout=500ms` and `timeToLive=1000ms`, the expiry notification
       arrives after the assertion was already evaluated. Fixed by calling
       `mockExpiredAdvisory.assertIsSatisfied(10_000)` with an explicit 
10-second
       timeout on the instance directly.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 .../sjms/producer/QueueProducerQoSTest.java        |  6 +++---
 ...leProducerCharsetUTFtoISOConvertBodyToTest.java |  9 ++++++--
 .../component/file/FileSortByExpressionTest.java   | 20 +++++++----------
 .../file/FileSortByIgnoreCaseExpressionTest.java   | 25 ++++++++++------------
 .../file/FileSortByNestedExpressionTest.java       | 14 ++++++------
 ...ultConsumerBridgeErrorHandlerContinuedTest.java |  7 +++---
 .../camel/support/cache/SimpleLRUCacheTest.java    | 11 +++++++---
 .../serving/services/container.properties          |  2 +-
 8 files changed, 47 insertions(+), 47 deletions(-)

diff --git 
a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/producer/QueueProducerQoSTest.java
 
b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/producer/QueueProducerQoSTest.java
index 459e8831eb45..300e3ba0f572 100644
--- 
a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/producer/QueueProducerQoSTest.java
+++ 
b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/producer/QueueProducerQoSTest.java
@@ -91,7 +91,7 @@ public class QueueProducerQoSTest extends CamelTestSupport {
             template.requestBody(endpoint, "test message");
         });
 
-        MockEndpoint.assertIsSatisfied(context);
+        mockExpiredAdvisory.assertIsSatisfied(10_000);
 
         assertEquals(0, service.countMessages(TEST_INOUT_DESTINATION_NAME),
                 "There were unexpected messages left in the queue: " + 
TEST_INOUT_DESTINATION_NAME);
@@ -104,7 +104,7 @@ public class QueueProducerQoSTest extends CamelTestSupport {
         String endpoint = String.format("sjms:queue:%s?timeToLive=1000", 
TEST_INONLY_DESTINATION_NAME);
         template.sendBody(endpoint, "test message");
 
-        MockEndpoint.assertIsSatisfied(context);
+        mockExpiredAdvisory.assertIsSatisfied(10_000);
 
         assertEquals(0, service.countMessages(TEST_INONLY_DESTINATION_NAME),
                 "There were unexpected messages left in the queue: " + 
TEST_INONLY_DESTINATION_NAME);
@@ -124,7 +124,7 @@ public class QueueProducerQoSTest extends CamelTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() {
-                from("sjms:topic:ExpiryQueue")
+                from("sjms:queue:ExpiryQueue")
                         .routeId(EXPIRED_MESSAGE_ROUTE_ID)
                         .log("Expired message")
                         .to(MOCK_EXPIRED_ADVISORY);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOConvertBodyToTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOConvertBodyToTest.java
index 937332ceb03a..433a6315d943 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOConvertBodyToTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOConvertBodyToTest.java
@@ -20,6 +20,7 @@ import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.ContextTestSupport;
@@ -45,16 +46,20 @@ class FileProducerCharsetUTFtoISOConvertBodyToTest extends 
ContextTestSupport {
 
     @BeforeEach
     void writeTestData() {
+        // Write to a temp file and atomically rename so the file consumer 
never
+        // sees a 0-byte file between newOutputStream() and close().
         assertDoesNotThrow(() -> {
-            try (OutputStream fos = 
Files.newOutputStream(testFile(INPUT_FILE))) {
+            Path tmp = testFile(INPUT_FILE + ".tmp");
+            try (OutputStream fos = Files.newOutputStream(tmp)) {
                 fos.write(DATA.getBytes(StandardCharsets.UTF_8));
             }
+            Files.move(tmp, testFile(INPUT_FILE), 
StandardCopyOption.ATOMIC_MOVE);
         }, "The test cannot run due to an I/O error");
     }
 
     @AfterEach
     void cleanupFile() {
-        assertDoesNotThrow(() -> Files.delete(testFile(OUTPUT_FILE)),
+        assertDoesNotThrow(() -> Files.deleteIfExists(testFile(OUTPUT_FILE)),
                 "The test cannot run due to an error cleaning up");
     }
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByExpressionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByExpressionTest.java
index b83c9667ac62..5f9283cdc4cf 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByExpressionTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByExpressionTest.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.component.file;
 
-import java.util.concurrent.TimeUnit;
-
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
@@ -42,6 +40,9 @@ public class FileSortByExpressionTest extends 
ContextTestSupport {
     public void testSortFiles() throws Exception {
         prepareFolder("a");
 
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello Paris", "Hello London", "Hello 
Copenhagen");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -49,17 +50,16 @@ public class FileSortByExpressionTest extends 
ContextTestSupport {
             }
         });
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceived("Hello Paris", "Hello London", "Hello 
Copenhagen");
-
-        // wait a bit for the file processing to complete
-        assertMockEndpointsSatisfied(1, TimeUnit.SECONDS);
+        assertMockEndpointsSatisfied();
     }
 
     @Test
     public void testSortFilesReverse() throws Exception {
         prepareFolder("b");
 
+        MockEndpoint reverse = getMockEndpoint("mock:reverse");
+        reverse.expectedBodiesReceived("Hello Copenhagen", "Hello London", 
"Hello Paris");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -68,11 +68,7 @@ public class FileSortByExpressionTest extends 
ContextTestSupport {
             }
         });
 
-        MockEndpoint reverse = getMockEndpoint("mock:reverse");
-        reverse.expectedBodiesReceived("Hello Copenhagen", "Hello London", 
"Hello Paris");
-
-        // wait a bit for the file processing to complete
-        assertMockEndpointsSatisfied(1, TimeUnit.SECONDS);
+        assertMockEndpointsSatisfied();
     }
 
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByIgnoreCaseExpressionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByIgnoreCaseExpressionTest.java
index 6bc19c45f217..cc56319c4280 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByIgnoreCaseExpressionTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByIgnoreCaseExpressionTest.java
@@ -29,7 +29,7 @@ import org.junit.jupiter.api.condition.OS;
  */
 @DisabledOnOs(value = { OS.LINUX },
               architectures = { "ppc64le" },
-              disabledReason = "This test does not run reliably multiple 
platforms (see CAMEL-21438)")
+              disabledReason = "This test does not run reliably on multiple 
platforms (see CAMEL-21438)")
 public class FileSortByIgnoreCaseExpressionTest extends ContextTestSupport {
 
     private void prepareFolder(String folder) {
@@ -45,16 +45,15 @@ public class FileSortByIgnoreCaseExpressionTest extends 
ContextTestSupport {
     public void testSortFilesByNameWithCase() throws Exception {
         prepareFolder("a");
 
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello London", "Hello Copenhagen", "Hello 
Paris");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
-                
from(fileUri("a/?sortBy=file:name&initialDelay=250&delay=1000")).convertBodyTo(String.class).to("mock:result");
+                
from(fileUri("a/?sortBy=file:name&initialDelay=0&delay=10")).convertBodyTo(String.class).to("mock:result");
             }
         });
-        context.start();
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceived("Hello London", "Hello Copenhagen", "Hello 
Paris");
 
         assertMockEndpointsSatisfied();
     }
@@ -63,6 +62,9 @@ public class FileSortByIgnoreCaseExpressionTest extends 
ContextTestSupport {
     public void testSortFilesByNameNoCase() throws Exception {
         prepareFolder("b");
 
+        MockEndpoint nocase = getMockEndpoint("mock:nocase");
+        nocase.expectedBodiesReceived("Hello Copenhagen", "Hello London", 
"Hello Paris");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -70,10 +72,6 @@ public class FileSortByIgnoreCaseExpressionTest extends 
ContextTestSupport {
                         .to("mock:nocase");
             }
         });
-        context.start();
-
-        MockEndpoint nocase = getMockEndpoint("mock:nocase");
-        nocase.expectedBodiesReceived("Hello Copenhagen", "Hello London", 
"Hello Paris");
 
         assertMockEndpointsSatisfied();
     }
@@ -82,6 +80,9 @@ public class FileSortByIgnoreCaseExpressionTest extends 
ContextTestSupport {
     public void testSortFilesByNameNoCaseReverse() throws Exception {
         prepareFolder("c");
 
+        MockEndpoint nocasereverse = getMockEndpoint("mock:nocasereverse");
+        nocasereverse.expectedBodiesReceived("Hello Paris", "Hello London", 
"Hello Copenhagen");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -89,10 +90,6 @@ public class FileSortByIgnoreCaseExpressionTest extends 
ContextTestSupport {
                         .to("mock:nocasereverse");
             }
         });
-        context.start();
-
-        MockEndpoint nocasereverse = getMockEndpoint("mock:nocasereverse");
-        nocasereverse.expectedBodiesReceived("Hello Paris", "Hello London", 
"Hello Copenhagen");
 
         assertMockEndpointsSatisfied();
     }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByNestedExpressionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByNestedExpressionTest.java
index 66030ce669ab..27b207d947e7 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByNestedExpressionTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileSortByNestedExpressionTest.java
@@ -42,6 +42,9 @@ public class FileSortByNestedExpressionTest extends 
ContextTestSupport {
     public void testSortNestedFiles() throws Exception {
         prepareFolder("a");
 
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello Dublin", "Hello London", "Hello 
Paris", "Hello Copenhagen");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -49,10 +52,6 @@ public class FileSortByNestedExpressionTest extends 
ContextTestSupport {
                         .to("mock:result");
             }
         });
-        context.start();
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceived("Hello Dublin", "Hello London", "Hello 
Paris", "Hello Copenhagen");
 
         assertMockEndpointsSatisfied();
     }
@@ -61,6 +60,9 @@ public class FileSortByNestedExpressionTest extends 
ContextTestSupport {
     public void testSortNestedFilesReverse() throws Exception {
         prepareFolder("b");
 
+        MockEndpoint reverse = getMockEndpoint("mock:reverse");
+        reverse.expectedBodiesReceived("Hello Paris", "Hello London", "Hello 
Dublin", "Hello Copenhagen");
+
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() {
@@ -68,10 +70,6 @@ public class FileSortByNestedExpressionTest extends 
ContextTestSupport {
                         .to("mock:reverse");
             }
         });
-        context.start();
-
-        MockEndpoint reverse = getMockEndpoint("mock:reverse");
-        reverse.expectedBodiesReceived("Hello Paris", "Hello London", "Hello 
Dublin", "Hello Copenhagen");
 
         assertMockEndpointsSatisfied();
     }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/DefaultConsumerBridgeErrorHandlerContinuedTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/DefaultConsumerBridgeErrorHandlerContinuedTest.java
index 8585cfa1d5cc..97ab97a271ff 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/processor/DefaultConsumerBridgeErrorHandlerContinuedTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/DefaultConsumerBridgeErrorHandlerContinuedTest.java
@@ -48,10 +48,9 @@ public class DefaultConsumerBridgeErrorHandlerContinuedTest 
extends ContextTestS
         getMockEndpoint("mock:onException").expectedMinimumMessageCount(1);
         getMockEndpoint("mock:subroute").expectedMinimumMessageCount(1);
 
-        // With continued(true), processing should continue after error 
handling
-        // However, since the consumer throws before creating a valid exchange,
-        // mock:result won't receive messages
-        getMockEndpoint("mock:result").expectedMessageCount(0);
+        // With continued(true), the exchange continues through the main route 
after error handling,
+        // so mock:result should receive messages.
+        getMockEndpoint("mock:result").expectedMinimumMessageCount(1);
 
         assertMockEndpointsSatisfied();
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/support/cache/SimpleLRUCacheTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/support/cache/SimpleLRUCacheTest.java
index ff5de7d670d1..8bb6534b1798 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/support/cache/SimpleLRUCacheTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/support/cache/SimpleLRUCacheTest.java
@@ -24,6 +24,7 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
 import org.junit.jupiter.api.parallel.Isolated;
@@ -501,8 +502,11 @@ class SimpleLRUCacheTest {
         }
         assertTrue(latch.await(20, TimeUnit.SECONDS),
                 "Should have completed within a reasonable timeframe. Latch 
at: " + latch.getCount());
-        assertEquals(maximumCacheSize, cache.size());
-        assertEquals(totalKeysPerThread * threads - maximumCacheSize, 
counter.get());
+        int expectedEvictions = totalKeysPerThread * threads - 
maximumCacheSize;
+        Awaitility.await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
+            assertEquals(maximumCacheSize, cache.size());
+            assertEquals(expectedEvictions, counter.get());
+        });
     }
 
     @ParameterizedTest
@@ -526,7 +530,8 @@ class SimpleLRUCacheTest {
         }
         assertTrue(latch.await(20, TimeUnit.SECONDS),
                 "Should have completed within a reasonable timeframe. Latch 
at: " + latch.getCount());
-        assertEquals(maximumCacheSize, cache.size());
+        Awaitility.await().atMost(10, TimeUnit.SECONDS)
+                .untilAsserted(() -> assertEquals(maximumCacheSize, 
cache.size()));
         counter.set(0);
         for (int j = 0; j < maximumCacheSize; j++) {
             cache.put(Integer.toString(j), "OK");
diff --git 
a/test-infra/camel-test-infra-tensorflow-serving/src/main/resources/org/apache/camel/test/infra/tensorflow/serving/services/container.properties
 
b/test-infra/camel-test-infra-tensorflow-serving/src/main/resources/org/apache/camel/test/infra/tensorflow/serving/services/container.properties
index 4bd04d3e4b9d..4944b1e5ed55 100644
--- 
a/test-infra/camel-test-infra-tensorflow-serving/src/main/resources/org/apache/camel/test/infra/tensorflow/serving/services/container.properties
+++ 
b/test-infra/camel-test-infra-tensorflow-serving/src/main/resources/org/apache/camel/test/infra/tensorflow/serving/services/container.properties
@@ -15,7 +15,7 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 tensorflow.serving.container=mirror.gcr.io/tensorflow/serving:2.19.1
-tensorflow.serving.container.aarch64=bitnami/tensorflow-serving:2.18.0
+tensorflow.serving.container.aarch64=mirror.gcr.io/bitnamilegacy/tensorflow-serving:2.19.1
 
tensorflow.serving.container.ppc64le=ibmcom/powerai:1.7.0-tensorflow-serving-ubuntu18.04-py37-ppc64le-21.035
 tensorflow.serving.container.ppc64le.version.include=ppc64le,ubuntu
 tensorflow.serving.container.ppc64le.version.exclude=x86_64,amd64,arm64

Reply via email to