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