This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch camel-23223-fix-flaky-test-managedmessagehistorya in repository https://gitbox.apache.org/repos/asf/camel.git
commit 3267a443fcb8b6319a0920fea2d9e61b2a8870f3 Author: Guillaume Nodet <[email protected]> AuthorDate: Sat Jul 4 17:17:26 2026 +0000 CAMEL-23223: Stabilize flaky ManagedMessageHistoryAutoConfigIT Replace the short 1-second Awaitility wait (which only waited for any log to appear) with untilAsserted using a 20-second timeout that retries the full set of metric assertions. This handles slow CI architectures where the OTel periodic reader may not export Camel metrics within 1 second, and avoids failures from incomplete early metric exports during message processing. Also make MemoryLogHandler thread-safe with CopyOnWriteArrayList since publish() is called from the OTel exporter thread while getLogs()/hasLogs() are called from the test thread. Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Guillaume Nodet <[email protected]> --- .../metrics/integration/MemoryLogHandler.java | 5 ++- .../ManagedMessageHistoryAutoConfigIT.java | 46 ++++++++++++---------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/MemoryLogHandler.java b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/MemoryLogHandler.java index 9ab5ac70f8d4..70a29a8bc99a 100644 --- a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/MemoryLogHandler.java +++ b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/MemoryLogHandler.java @@ -18,11 +18,14 @@ package org.apache.camel.opentelemetry.metrics.integration; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.ConsoleHandler; import java.util.logging.LogRecord; public class MemoryLogHandler extends ConsoleHandler { - private List<LogRecord> logs = new ArrayList<>(); + // CopyOnWriteArrayList for thread safety: publish() is called from the OTel + // exporter thread while hasLogs()/getLogs() are called from the test thread + private final List<LogRecord> logs = new CopyOnWriteArrayList<>(); public MemoryLogHandler() { super(); diff --git a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java index 9fbf9a0d7a94..0621aeaecd5c 100644 --- a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java +++ b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java @@ -98,30 +98,34 @@ public class ManagedMessageHistoryAutoConfigIT extends CamelTestSupport { MockEndpoint.assertIsSatisfied(context); - await().atMost(Duration.ofMillis(1000L)).until(handler::hasLogs); - - List<LogRecord> logs = new ArrayList<>(handler.getLogs()); - assertFalse(logs.isEmpty(), "No metrics were exported"); - int dataCount = 0; - for (LogRecord log : logs) { - if (log.getParameters() != null && log.getParameters().length > 0) { - MetricData metricData = (MetricData) log.getParameters()[0]; - // Skip non-Camel metrics (e.g. otel.sdk.* internal metrics added in OTel 1.60+) - if (!metricData.getName().startsWith("camel.")) { - continue; + // Use Awaitility to retry assertions until the OTel periodic reader has exported + // Camel metrics. On slow CI architectures the first export may be delayed well + // beyond the 300ms export interval. Assert on the last exported Camel metric data + // because earlier exports during message processing may contain incomplete data. + await().atMost(Duration.ofSeconds(20)).untilAsserted(() -> { + List<LogRecord> logs = new ArrayList<>(handler.getLogs()); + assertFalse(logs.isEmpty(), "No metrics were exported"); + + MetricData lastCamelMetric = null; + for (LogRecord log : logs) { + if (log.getParameters() != null && log.getParameters().length > 0) { + MetricData metricData = (MetricData) log.getParameters()[0]; + // Skip non-Camel metrics (e.g. otel.sdk.* internal metrics added in OTel 1.60+) + if (!metricData.getName().startsWith("camel.")) { + continue; + } + assertEquals(DEFAULT_CAMEL_MESSAGE_HISTORY_METER_NAME, metricData.getName()); + lastCamelMetric = metricData; } - assertEquals(DEFAULT_CAMEL_MESSAGE_HISTORY_METER_NAME, metricData.getName()); - - assertPointDataForRouteId(metricData, "route1"); + } + assertThat(lastCamelMetric).as("No Camel metric data found").isNotNull(); - assertMetricDataHasNodeId(metricData, "route1", "foo"); - assertMetricDataHasNodeId(metricData, "route2", "bar"); - assertMetricDataHasNodeId(metricData, "route2", "baz"); + assertPointDataForRouteId(lastCamelMetric, "route1"); - dataCount++; - } - } - assertTrue(dataCount > 0, "No metric data found"); + assertMetricDataHasNodeId(lastCamelMetric, "route1", "foo"); + assertMetricDataHasNodeId(lastCamelMetric, "route2", "bar"); + assertMetricDataHasNodeId(lastCamelMetric, "route2", "baz"); + }); } private void assertMetricDataHasNodeId(MetricData metricData, String routeId, String nodeId) {
