Skip to content

Commit f543f06

Browse files
committed
WIP
1 parent d6d9076 commit f543f06

4 files changed

Lines changed: 39 additions & 58 deletions

File tree

dd-smoke-tests/spring-boot-rabbit/src/test/java/datadog/smoketest/SpringBootRabbitSmokeTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ void roundtripsProduceFullAmqpTraceStructure() throws IOException {
140140
.traces()
141141
.assertTraces(
142142
TIMEOUT_SECONDS,
143-
o -> o.unordered().ignoreAdditionalTraces(),
143+
o -> o.unorder().ignoreAdditionalTraces(),
144144
expected.toArray(new TraceMatcher[0]));
145145
}
146146

dd-smoke-tests/src/main/java/datadog/smoketest/backend/Traces.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ public void assertTraces(TraceMatcher... matchers) {
7373

7474
/**
7575
* As {@link #assertTraces(TraceMatcher...)} with options (e.g. {@code
76-
* SmokeTraceAssertions.IGNORE_ADDITIONAL_TRACES} / {@code SORT_BY_ROOT_SPAN_ID}).
76+
* SmokeTraceAssertions.UNORDERED} / {@code IGNORE_ADDITIONAL_TRACES} / {@code
77+
* SORT_BY_START_TIME}).
7778
*/
7879
public void assertTraces(
7980
UnaryOperator<SmokeTraceAssertions.Options> options, TraceMatcher... matchers) {

dd-smoke-tests/src/main/java/datadog/smoketest/trace/SmokeTraceAssertions.java

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import datadog.trace.test.agent.decoder.DecodedSpan;
99
import datadog.trace.test.agent.decoder.DecodedTrace;
1010
import java.util.ArrayList;
11+
import java.util.BitSet;
1112
import java.util.Comparator;
1213
import java.util.List;
1314
import java.util.function.UnaryOperator;
@@ -24,26 +25,33 @@
2425
* assertTraces(traces, trace(span().operationName("servlet.request").resourceName("GET /greeting")));
2526
* }</pre>
2627
*
27-
* <p>A single matching algorithm is tuned by three orthogonal, combinable {@link Options}:
28+
* <p>A single matching algorithm is tuned by three combinable {@link Options}:
2829
*
2930
* <ul>
30-
* <li>{@link #SORT_BY_START_TIME} / {@link #SORT_BY_ROOT_SPAN_ID} (the {@code sorter}) — sort the
31-
* received traces before matching.
31+
* <li>{@link #SORT_BY_START_TIME} (the {@code sorter}) — sort the received traces before matching,
32+
* making positional matching deterministic.
3233
* <li>{@link #UNORDERED} — a matcher may match <em>any</em> distinct (unconsumed) trace rather
33-
* than the one at its position. Without a sorter this is fully order-independent;
34-
* <em>with</em> a sorter it is forward-only (once a matcher takes the trace at sorted
35-
* position <i>p</i>, the next matcher can only look at positions after <i>p</i>) — i.e. match
36-
* as a subsequence in sorted order.
34+
* than the one at its position; the received order stops mattering (so a {@code sorter} has no
35+
* effect in this mode).
3736
* <li>{@link #IGNORE_ADDITIONAL_TRACES} — don't require every received trace to be matched; extra
3837
* traces are ignored (a subset assertion). Without it, the counts must be equal.
3938
* </ul>
4039
*
41-
* <p>The default (no options) is thus count-exact positional matching (matcher <i>i</i> ↔ trace
42-
* <i>i</i>, received order). Combine flags with the fluent {@link Options} — e.g. {@code o ->
43-
* o.unordered().ignoreAdditionalTraces()} — to assert only the traces you care about in a
44-
* collection that also holds unrelated or non-deterministically-ordered ones (e.g. a distributed
45-
* test where connection-setup commands land as their own traces). The traces come from a {@code
46-
* TraceBackend} (mock or test-agent), both decoded to {@link DecodedTrace}.
40+
* <p>The useful combinations are:
41+
*
42+
* <ul>
43+
* <li><b>default</b> (optionally with a {@code sorter}) — count-exact positional: matcher
44+
* <i>i</i> ↔ trace <i>i</i>.
45+
* <li><b>{@code sorter} + {@code ignoreAdditionalTraces}</b> — ordered subsequence: match in
46+
* sorted order, skipping the traces no matcher claims.
47+
* <li><b>{@code unordered} + {@code ignoreAdditionalTraces}</b> — any-order subset: match the
48+
* traces you care about and ignore the rest (e.g. a distributed test where connection-setup
49+
* commands land as their own traces alongside the request traces).
50+
* </ul>
51+
*
52+
* <p>Combine flags with the fluent {@link Options}, e.g. {@code o ->
53+
* o.unordered().ignoreAdditionalTraces()}. The traces come from a {@code TraceBackend} (mock or
54+
* test-agent), both decoded to {@link DecodedTrace}.
4755
*/
4856
public final class SmokeTraceAssertions {
4957
/** Sorts traces by the earliest span start time. */
@@ -55,11 +63,11 @@ public final class SmokeTraceAssertions {
5563
Options::ignoreAdditionalTraces;
5664

5765
/** Let each matcher match any distinct trace rather than the one at its position. */
58-
public static final UnaryOperator<Options> UNORDERED = Options::unordered;
66+
public static final UnaryOperator<Options> UNORDERED = Options::unorder;
5967

6068
/** Sorts traces by earliest span start time before matching. */
6169
public static final UnaryOperator<Options> SORT_BY_START_TIME =
62-
options -> options.sorter(TRACE_START_TIME_COMPARATOR);
70+
options -> options.sort(TRACE_START_TIME_COMPARATOR);
6371

6472
private SmokeTraceAssertions() {}
6573

@@ -107,31 +115,26 @@ public static void assertTraces(
107115
traces = new ArrayList<>(traces);
108116
traces.sort(opts.sorter);
109117
}
118+
// Assert traces
110119
boolean strictPositional = !opts.unordered && !opts.ignoreAdditionalTraces;
111-
// Record matched traces for unordered mode
112-
boolean[] traceMatched = new boolean[traceCount];
113-
// Record last matching trace index for ignoreAdditionalTraces mode
114-
int floor = 0;
115-
120+
BitSet skippedTraces = new BitSet(traceCount);
116121
for (int matcherIndex = 0; matcherIndex < matchers.length; matcherIndex++) {
117122
TraceMatcher matcher = matchers[matcherIndex];
118123
if (strictPositional) {
119124
matcher.assertTrace(traces.get(matcherIndex).getSpans(), matcherIndex);
120125
continue;
121126
}
122-
123127
boolean matched = false;
124-
for (int traceIndex = floor; traceIndex < traceCount; traceIndex++) {
125-
// Skipped already matched traces - unordered mode only
126-
if (traceMatched[traceIndex]) {
128+
for (int traceIndex = skippedTraces.nextClearBit(0); traceIndex < traceCount; traceIndex++) {
129+
if (skippedTraces.get(traceIndex)) {
127130
continue;
128131
}
129132
if (matcher.matches(traces.get(traceIndex).getSpans(), matcherIndex)) {
130133
matched = true;
131134
if (opts.unordered) {
132-
traceMatched[traceIndex] = true;
135+
skippedTraces.set(traceIndex);
133136
} else {
134-
floor = traceIndex + 1;
137+
skippedTraces.set(0, traceIndex);
135138
}
136139
break;
137140
}
@@ -150,25 +153,24 @@ private static long earliestStart(DecodedTrace trace) {
150153
return start == MAX_VALUE ? 0L : start;
151154
}
152155

153-
/** Trace-collection matching options; see the class doc for how they combine. */
154156
public static final class Options {
155157
boolean ignoreAdditionalTraces = false;
156158
boolean unordered = false;
157-
Comparator<DecodedTrace> sorter = null; // null => keep received order
159+
Comparator<DecodedTrace> sorter = null;
158160

159-
/** Ignore received traces beyond those the matchers consume (a subset assertion). */
160161
public Options ignoreAdditionalTraces() {
161162
this.ignoreAdditionalTraces = true;
162163
return this;
163164
}
164165

165-
/** Let each matcher match any distinct trace (forward-only when a {@link #sorter} is set). */
166-
public Options unordered() {
166+
public Options unorder() {
167167
this.unordered = true;
168+
this.sorter = null;
168169
return this;
169170
}
170171

171-
public Options sorter(Comparator<DecodedTrace> sorter) {
172+
public Options sort(Comparator<DecodedTrace> sorter) {
173+
this.unordered = false;
172174
this.sorter = sorter;
173175
return this;
174176
}

dd-smoke-tests/src/test/java/datadog/smoketest/trace/SmokeMatcherTest.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ void unorderedMatchesAnyOrder() {
127127
// order).
128128
assertTraces(
129129
traces,
130-
options -> options.unordered().ignoreAdditionalTraces(),
130+
options -> options.unorder().ignoreAdditionalTraces(),
131131
trace(span().operationName("root-b").root()),
132132
trace(span().operationName("root-a").root()));
133133
}
@@ -141,33 +141,11 @@ void unorderedRequiresDistinctTraces() {
141141
() ->
142142
assertTraces(
143143
traces,
144-
options -> options.unordered().ignoreAdditionalTraces(),
144+
options -> options.unorder().ignoreAdditionalTraces(),
145145
trace(span().operationName("root-a").root()),
146146
trace(span().operationName("root-a").root())));
147147
}
148148

149-
// @Test
150-
// void unorderedWithSorterIsForwardOnly() {
151-
// List<DecodedTrace> traces = TestAgentTraceDecoder.decode(TWO_TRACES);
152-
// // Sorted by root span id => [root-b (400), root-a (500)]. With a sorter, an unordered match is
153-
// // forward-only: matchers in sorted order match...
154-
// assertTraces(
155-
// traces,
156-
// options -> options.unordered().sorter(SmokeTraceAssertions.TRACE_ROOT_SPAN_ID_COMPARATOR),
157-
// trace(span().operationName("root-b").root()),
158-
// trace(span().operationName("root-a").root()));
159-
// // ...but reversed they don't (root-a is matched at position 1, leaving nothing after it).
160-
// assertThrows(
161-
// AssertionError.class,
162-
// () ->
163-
// assertTraces(
164-
// traces,
165-
// options ->
166-
// options.unordered().sorter(SmokeTraceAssertions.TRACE_ROOT_SPAN_ID_COMPARATOR),
167-
// trace(span().operationName("root-a").root()),
168-
// trace(span().operationName("root-b").root())));
169-
// }
170-
171149
private static String spanJson(String name, long id, long parent, long start) {
172150
return "{\"service\":\"s\",\"name\":\""
173151
+ name

0 commit comments

Comments
 (0)