This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch fix-flaky-test-spanpropagationupstreamtest-20-fl in repository https://gitbox.apache.org/repos/asf/camel.git
commit f3333d0bf2b0f35a63461817920104f89d96820a Author: Guillaume Nodet <[email protected]> AuthorDate: Fri Jul 10 15:00:03 2026 +0000 CAMEL-23993: Fix flaky SpanPropagationUpstreamTest - add tie-breaking to SpanComparator SpanComparator sorted spans by startEpochNanos only. When multiple spans started at the same nanosecond (common on fast systems), Java's TimSort preserved InMemorySpanExporter insertion order which is end-order (inner spans first), the reverse of the creation order tests expect. Add endEpochNanos descending as a secondary sort key. Parent spans always end after their children, so this deterministically places parents first when start times tie, matching the expected hierarchy order. Also fixes an integer overflow bug in the mock-based comparators (camel-telemetry, camel-telemetry-dev) that used (int)(longA - longB) instead of Long.compare(). Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../micrometer/observability/CamelOpenTelemetryExtension.java | 10 +++++++--- .../camel/opentelemetry2/CamelOpenTelemetryExtension.java | 10 +++++++--- .../src/main/java/org/apache/camel/telemetrydev/DevTrace.java | 10 +++++++--- .../test/java/org/apache/camel/telemetry/mock/MockTrace.java | 8 +++++++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/CamelOpenTelemetryExtension.java b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/CamelOpenTelemetryExtension.java index f212f37127b6..d49d08755c04 100644 --- a/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/CamelOpenTelemetryExtension.java +++ b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/CamelOpenTelemetryExtension.java @@ -217,9 +217,13 @@ final class CamelOpenTelemetryExtension implements BeforeEachCallback, AfterEach class SpanComparator implements Comparator<SpanData> { @Override public int compare(SpanData a, SpanData b) { - long nanosA = a.getStartEpochNanos(); - long nanosB = b.getStartEpochNanos(); - return Long.compare(nanosA, nanosB); + int cmp = Long.compare(a.getStartEpochNanos(), b.getStartEpochNanos()); + if (cmp != 0) { + return cmp; + } + // When start times tie, sort by end time descending so that parent + // spans (which end after their children) come first. + return Long.compare(b.getEndEpochNanos(), a.getEndEpochNanos()); } } } diff --git a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java index 5d548203bd00..fae8e8f683b2 100644 --- a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java +++ b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java @@ -204,9 +204,13 @@ final class CamelOpenTelemetryExtension implements BeforeEachCallback, AfterEach class SpanComparator implements Comparator<SpanData> { @Override public int compare(SpanData a, SpanData b) { - Long nanosA = a.getStartEpochNanos(); - Long nanosB = b.getStartEpochNanos(); - return Long.compare(nanosA, nanosB); + int cmp = Long.compare(a.getStartEpochNanos(), b.getStartEpochNanos()); + if (cmp != 0) { + return cmp; + } + // When start times tie, sort by end time descending so that parent + // spans (which end after their children) come first. + return Long.compare(b.getEndEpochNanos(), a.getEndEpochNanos()); } } } diff --git a/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevTrace.java b/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevTrace.java index 0029e12e7271..3e3f74aa8eaf 100644 --- a/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevTrace.java +++ b/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevTrace.java @@ -132,8 +132,12 @@ public class DevTrace implements Iterable<DevSpanAdapter> { class SpanComparator implements Comparator<DevSpanAdapter> { @Override public int compare(DevSpanAdapter a, DevSpanAdapter b) { - DevSpanAdapter msa = (DevSpanAdapter) a; - DevSpanAdapter msb = (DevSpanAdapter) b; - return (int) (Long.parseLong(msa.getTag("initTimestamp")) - Long.parseLong(msb.getTag("initTimestamp"))); + int cmp = Long.compare(Long.parseLong(a.getTag("initTimestamp")), Long.parseLong(b.getTag("initTimestamp"))); + if (cmp != 0) { + return cmp; + } + // When start times tie, sort by end time descending so that parent + // spans (which end after their children) come first. + return Long.compare(Long.parseLong(b.getTag("endTimestamp")), Long.parseLong(a.getTag("endTimestamp"))); } } diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTrace.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTrace.java index 6244157eab18..447185add0a9 100644 --- a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTrace.java +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTrace.java @@ -52,6 +52,12 @@ class SpanComparator implements Comparator<Span> { // cast to get timestamp without changing the Span interface MockSpanAdapter msa = (MockSpanAdapter) a; MockSpanAdapter msb = (MockSpanAdapter) b; - return (int) (Long.parseLong(msa.getTag("initTimestamp")) - Long.parseLong(msb.getTag("initTimestamp"))); + int cmp = Long.compare(Long.parseLong(msa.getTag("initTimestamp")), Long.parseLong(msb.getTag("initTimestamp"))); + if (cmp != 0) { + return cmp; + } + // When start times tie, sort by end time descending so that parent + // spans (which end after their children) come first. + return Long.compare(Long.parseLong(msb.getTag("endTimestamp")), Long.parseLong(msa.getTag("endTimestamp"))); } }
