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 5dfd6e6cc358 CAMEL-24036: Fix flaky AsyncWiretapTest across telemetry
modules
5dfd6e6cc358 is described below
commit 5dfd6e6cc3587b5c6292174944886e370dc10417
Author: Omar Atie <[email protected]>
AuthorDate: Wed Aug 5 02:14:20 2026 -0700
CAMEL-24036: Fix flaky AsyncWiretapTest across telemetry modules
Replace Thread.sleep, short mock timeouts, and missing trace waits with
Awaitility polling and MockEndpoint.assertIsSatisfied(30s) across
camel-telemetry, camel-telemetry-dev, camel-opentelemetry2, and
camel-micrometer-observability modules.
Closes #25331
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../micrometer/observability/AsyncWiretapTest.java | 37 +++++++++++++--------
.../camel/opentelemetry2/AsyncWiretapTest.java | 37 +++++++++++++--------
.../camel/telemetrydev/AsyncWiretapTest.java | 38 ++++++++++++----------
.../apache/camel/telemetry/AsyncWiretapTest.java | 38 ++++++++++++----------
4 files changed, 88 insertions(+), 62 deletions(-)
diff --git
a/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/AsyncWiretapTest.java
b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/AsyncWiretapTest.java
index 225e9d109840..1d8918c893e0 100644
---
a/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/AsyncWiretapTest.java
+++
b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/AsyncWiretapTest.java
@@ -16,9 +16,9 @@
*/
package org.apache.camel.micrometer.observability;
-import java.io.IOException;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.SpanId;
@@ -30,6 +30,7 @@ import
org.apache.camel.micrometer.observability.CamelOpenTelemetryExtension.Ote
import org.apache.camel.telemetry.Op;
import org.junit.jupiter.api.Test;
+import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -38,33 +39,41 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* WiretappedRouteTest tests the execution of a new spin off component which
would create a new exchange,
* for example, using the wiretap component.
*/
-public class AsyncWiretapTest extends
MicrometerObservabilityTracerPropagationTestSupport {
+class AsyncWiretapTest extends
MicrometerObservabilityTracerPropagationTestSupport {
+
+ private static final int MESSAGE_COUNT = 10;
+ private static final int SPAN_COUNT = 7;
+ private static final long TIMEOUT_SECONDS = 30;
@Test
- void testRouteMultipleRequests() throws InterruptedException, IOException {
- int j = 10;
+ void testRouteMultipleRequests() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:end");
- mock.expectedMessageCount(j);
- mock.setAssertPeriod(5000);
- for (int i = 0; i < j; i++) {
+ mock.expectedMessageCount(MESSAGE_COUNT);
+ for (int i = 0; i < MESSAGE_COUNT; i++) {
context.createProducerTemplate().sendBody("direct:start",
"Hello!");
}
- mock.assertIsSatisfied(1000);
+ MockEndpoint.assertIsSatisfied(context, TIMEOUT_SECONDS,
TimeUnit.SECONDS);
+ // Wait for async trace export to complete — spans are written
asynchronously
+ // after exchange processing, so we poll until all traces with
expected spans arrive.
+ await().atMost(TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .pollInterval(100, TimeUnit.MILLISECONDS)
+ .untilAsserted(() -> {
+ Map<String, OtelTrace> traces = otelExtension.getTraces();
+ assertEquals(MESSAGE_COUNT, traces.size());
+ for (OtelTrace trace : traces.values()) {
+ assertEquals(SPAN_COUNT, trace.getSpans().size());
+ }
+ });
Map<String, OtelTrace> traces = otelExtension.getTraces();
- // Each trace should have a unique trace id. It is enough to assert
that
- // the number of elements in the map is the same of the requests to
prove
- // all traces have been generated uniquely.
- assertEquals(j, traces.size());
// Each trace should have the same structure
for (OtelTrace trace : traces.values()) {
checkTrace(trace, "Hello!");
}
-
}
private void checkTrace(OtelTrace trace, String expectedBody) {
List<SpanData> spans = trace.getSpans();
- assertEquals(7, spans.size());
+ assertEquals(SPAN_COUNT, spans.size());
SpanData testProducer = getSpan(spans, "direct://start",
Op.EVENT_SENT);
SpanData direct = getSpan(spans, "direct://start", Op.EVENT_RECEIVED);
SpanData wiretapDirectTo = getSpan(spans, "direct://tap",
Op.EVENT_SENT);
diff --git
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
index 81075b3b82d4..44220e59dc55 100644
---
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
+++
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
@@ -16,9 +16,9 @@
*/
package org.apache.camel.opentelemetry2;
-import java.io.IOException;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.sdk.trace.data.SpanData;
@@ -31,6 +31,7 @@ import
org.apache.camel.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
import org.apache.camel.telemetry.Op;
import org.junit.jupiter.api.Test;
+import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -40,7 +41,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* WiretappedRouteTest tests the execution of a new spin off component which
would create a new exchange, for example,
* using the wiretap component.
*/
-public class AsyncWiretapTest extends OpenTelemetryTracerTestSupport {
+class AsyncWiretapTest extends OpenTelemetryTracerTestSupport {
+
+ private static final int MESSAGE_COUNT = 10;
+ private static final int SPAN_COUNT = 7;
+ private static final long TIMEOUT_SECONDS = 30;
@Override
protected CamelContext createCamelContext() throws Exception {
@@ -55,30 +60,34 @@ public class AsyncWiretapTest extends
OpenTelemetryTracerTestSupport {
}
@Test
- void testRouteMultipleRequests() throws InterruptedException, IOException {
- int j = 10;
+ void testRouteMultipleRequests() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:end");
- mock.expectedMessageCount(j);
- mock.setAssertPeriod(5000);
- for (int i = 0; i < j; i++) {
+ mock.expectedMessageCount(MESSAGE_COUNT);
+ for (int i = 0; i < MESSAGE_COUNT; i++) {
context.createProducerTemplate().sendBody("direct:start",
"Hello!");
}
- mock.assertIsSatisfied(1000);
+ MockEndpoint.assertIsSatisfied(context, TIMEOUT_SECONDS,
TimeUnit.SECONDS);
+ // Wait for async trace export to complete — spans are written
asynchronously
+ // after exchange processing, so we poll until all traces with
expected spans arrive.
+ await().atMost(TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .pollInterval(100, TimeUnit.MILLISECONDS)
+ .untilAsserted(() -> {
+ Map<String, OtelTrace> traces = otelExtension.getTraces();
+ assertEquals(MESSAGE_COUNT, traces.size());
+ for (OtelTrace trace : traces.values()) {
+ assertEquals(SPAN_COUNT, trace.getSpans().size());
+ }
+ });
Map<String, OtelTrace> traces = otelExtension.getTraces();
- // Each trace should have a unique trace id. It is enough to assert
that
- // the number of elements in the map is the same of the requests to
prove
- // all traces have been generated uniquely.
- assertEquals(j, traces.size());
// Each trace should have the same structure
for (OtelTrace trace : traces.values()) {
checkTrace(trace, "Hello!");
}
-
}
private void checkTrace(OtelTrace trace, String expectedBody) {
List<SpanData> spans = trace.getSpans();
- assertEquals(7, spans.size());
+ assertEquals(SPAN_COUNT, spans.size());
SpanData testProducer = OpenTelemetryTracerTestSupport.getSpan(spans,
"direct://start", Op.EVENT_SENT);
SpanData direct = OpenTelemetryTracerTestSupport.getSpan(spans,
"direct://start", Op.EVENT_RECEIVED);
SpanData wiretapDirectTo =
OpenTelemetryTracerTestSupport.getSpan(spans, "direct://tap", Op.EVENT_SENT);
diff --git
a/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/AsyncWiretapTest.java
b/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/AsyncWiretapTest.java
index a7406f063d08..4f4b89777a1c 100644
---
a/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/AsyncWiretapTest.java
+++
b/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/AsyncWiretapTest.java
@@ -37,7 +37,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
* WiretappedRouteTest tests the execution of a new spin off component which
would create a new exchange, for example,
* using the wiretap component.
*/
-public class AsyncWiretapTest extends TelemetryDevTracerTestSupport {
+class AsyncWiretapTest extends TelemetryDevTracerTestSupport {
+
+ private static final int MESSAGE_COUNT = 10;
+ private static final int SPAN_COUNT = 7;
+ private static final long TIMEOUT_SECONDS = 30;
@Override
protected CamelContext createCamelContext() throws Exception {
@@ -52,27 +56,27 @@ public class AsyncWiretapTest extends
TelemetryDevTracerTestSupport {
@Test
void testRouteMultipleRequests() throws Exception {
- int j = 10;
MockEndpoint mock = getMockEndpoint("mock:end");
- mock.expectedMessageCount(j);
- for (int i = 0; i < j; i++) {
+ mock.expectedMessageCount(MESSAGE_COUNT);
+ for (int i = 0; i < MESSAGE_COUNT; i++) {
context.createProducerTemplate().sendBody("direct:start",
"Hello!");
}
- MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
+ MockEndpoint.assertIsSatisfied(context, TIMEOUT_SECONDS,
TimeUnit.SECONDS);
// Wait for async trace writing to complete — traces are written
asynchronously
// after exchange processing, so we poll until all traces with
expected spans arrive.
- await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
- Map<String, DevTrace> traces = tracesFromLog();
- assertEquals(j, traces.size());
- for (DevTrace trace : traces.values()) {
- assertEquals(7, trace.getSpans().size());
- }
- });
+ await().atMost(TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .pollInterval(100, TimeUnit.MILLISECONDS)
+ .untilAsserted(() -> {
+ Map<String, DevTrace> traces = tracesFromLog();
+ assertEquals(MESSAGE_COUNT, traces.size());
+ for (DevTrace trace : traces.values()) {
+ assertEquals(SPAN_COUNT, trace.getSpans().size());
+ for (DevSpanAdapter span : trace.getSpans()) {
+ assertEquals("true", span.getTag("isDone"));
+ }
+ }
+ });
Map<String, DevTrace> traces = tracesFromLog();
- // Each trace should have a unique trace id. It is enough to assert
that
- // the number of elements in the map is the same of the requests to
prove
- // all traces have been generated uniquely.
- assertEquals(j, traces.size());
// Each trace should have the same structure
for (DevTrace trace : traces.values()) {
checkTrace(trace, "Hello!");
@@ -81,7 +85,7 @@ public class AsyncWiretapTest extends
TelemetryDevTracerTestSupport {
private void checkTrace(DevTrace trace, String expectedBody) {
List<DevSpanAdapter> spans = trace.getSpans();
- assertEquals(7, spans.size());
+ assertEquals(SPAN_COUNT, spans.size());
DevSpanAdapter testProducer =
TelemetryDevTracerTestSupport.getSpan(spans, "direct://start", Op.EVENT_SENT);
DevSpanAdapter direct = TelemetryDevTracerTestSupport.getSpan(spans,
"direct://start", Op.EVENT_RECEIVED);
DevSpanAdapter wiretapDirectTo =
TelemetryDevTracerTestSupport.getSpan(spans, "direct://tap", Op.EVENT_SENT);
diff --git
a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/AsyncWiretapTest.java
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/AsyncWiretapTest.java
index f7988573f4a3..291bc98dc293 100644
---
a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/AsyncWiretapTest.java
+++
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/AsyncWiretapTest.java
@@ -40,7 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
* WiretappedRouteTest tests the execution of a new spin off component which
would create a new exchange, for example,
* using the wiretap component.
*/
-public class AsyncWiretapTest extends ExchangeTestSupport {
+class AsyncWiretapTest extends ExchangeTestSupport {
+
+ private static final int MESSAGE_COUNT = 10;
+ private static final int SPAN_COUNT = 7;
+ private static final long TIMEOUT_SECONDS = 30;
MockTracer mockTracer;
@@ -56,27 +60,27 @@ public class AsyncWiretapTest extends ExchangeTestSupport {
@Test
void testRouteMultipleRequests() throws Exception {
- int j = 10;
MockEndpoint mock = getMockEndpoint("mock:end");
- mock.expectedMessageCount(j);
- for (int i = 0; i < j; i++) {
+ mock.expectedMessageCount(MESSAGE_COUNT);
+ for (int i = 0; i < MESSAGE_COUNT; i++) {
context.createProducerTemplate().sendBody("direct:start",
"Hello!");
}
- MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
+ MockEndpoint.assertIsSatisfied(context, TIMEOUT_SECONDS,
TimeUnit.SECONDS);
// Wait for async trace writing to complete — traces are written
asynchronously
// after exchange processing, so we poll until all traces with
expected spans arrive.
- await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
- Map<String, MockTrace> traces = mockTracer.traces();
- assertEquals(j, traces.size());
- for (MockTrace trace : traces.values()) {
- assertEquals(7, trace.spans().size());
- }
- });
+ await().atMost(TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .pollInterval(100, TimeUnit.MILLISECONDS)
+ .untilAsserted(() -> {
+ Map<String, MockTrace> traces = mockTracer.traces();
+ assertEquals(MESSAGE_COUNT, traces.size());
+ for (MockTrace trace : traces.values()) {
+ assertEquals(SPAN_COUNT, trace.spans().size());
+ for (Span span : trace.spans()) {
+ assertEquals("true", ((MockSpanAdapter)
span).getTag("isDone"));
+ }
+ }
+ });
Map<String, MockTrace> traces = mockTracer.traces();
- // Each trace should have a unique trace id. It is enough to assert
that
- // the number of elements in the map is the same of the requests to
prove
- // all traces have been generated uniquely.
- assertEquals(j, traces.size());
// Each trace should have the same structure
for (MockTrace trace : traces.values()) {
checkTrace(trace, "Hello!");
@@ -85,7 +89,7 @@ public class AsyncWiretapTest extends ExchangeTestSupport {
private void checkTrace(MockTrace trace, String expectedBody) {
List<Span> spans = trace.spans();
- assertEquals(7, spans.size());
+ assertEquals(SPAN_COUNT, spans.size());
// Cast to implementation object to be able to
// inspect the status of the Span.
MockSpanAdapter testProducer = SpanTestSupport.getSpan(spans,
"direct://start", Op.EVENT_SENT);