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")));
     }
 }

Reply via email to