diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index a88c00db14e..86904e56952 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -82,6 +82,7 @@ public final class ConfigDefaults { new LinkedHashSet<>(asList(DATADOG, TRACECONTEXT, BAGGAGE)); static final Set DEFAULT_PROPAGATION_STYLE = new LinkedHashSet<>(asList(PropagationStyle.DATADOG)); + public static final boolean DEFAULT_PROPAGATION_B3_PADDING_ENABLED = true; static final int DEFAULT_TRACE_BAGGAGE_MAX_ITEMS = 64; static final int DEFAULT_TRACE_BAGGAGE_MAX_BYTES = 8192; static final List DEFAULT_TRACE_BAGGAGE_TAG_KEYS = diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 49d808ea835..375480a8792 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -115,7 +115,6 @@ import datadog.trace.util.AgentTaskScheduler; import java.io.IOException; import java.lang.ref.WeakReference; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -140,11 +139,8 @@ */ public class CoreTracer implements AgentTracer.TracerAPI, TracerFlare.Reporter { private static final Logger log = LoggerFactory.getLogger(CoreTracer.class); - // UINT64 max value - public static final BigInteger TRACE_ID_MAX = - BigInteger.valueOf(2).pow(64).subtract(BigInteger.ONE); - public static final CoreTracerBuilder builder() { + public static CoreTracerBuilder builder() { return new CoreTracerBuilder(); } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpExtractorTest.java index d171f282323..9ec455ff233 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpExtractorTest.java @@ -1,5 +1,6 @@ package datadog.trace.core.propagation; +import static datadog.trace.api.config.TracerConfig.PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED; import static datadog.trace.bootstrap.ActiveSubsystems.APPSEC_ACTIVE; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; import static datadog.trace.core.propagation.B3HttpCodec.B3_KEY; @@ -9,6 +10,7 @@ import static datadog.trace.core.propagation.B3HttpCodec.SAMPLING_PRIORITY_KEY; import static datadog.trace.core.propagation.B3HttpCodec.SPAN_ID_KEY; import static datadog.trace.core.propagation.B3HttpCodec.TRACE_ID_KEY; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -25,7 +27,6 @@ import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; import datadog.trace.test.util.DDJavaSpecification; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -33,7 +34,7 @@ import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; -@WithConfig(key = "propagation.extract.log_header_names.enabled", value = "true") +@WithConfig(key = PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED, value = "true") class B3HttpExtractorTest extends DDJavaSpecification { private static final String SOME_HEADER = "SOME_HEADER"; private static final String SOME_TAG = "some-tag"; @@ -74,14 +75,14 @@ void extractHttpHeaders( String spanIdHex, Integer samplingPriority, @ConvertWith(PrioritySamplingConverter.class) byte expectedSamplingPriority) { - Map headers = new HashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceIdHex); - headers.put(SPAN_ID_KEY.toUpperCase(), spanIdHex); - headers.put(SOME_HEADER, SOME_VALUE); - if (samplingPriority != null) { - headers.put(SAMPLING_PRIORITY_KEY, samplingPriority.toString()); - } + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceIdHex, + SPAN_ID_KEY, spanIdHex, + SOME_HEADER, SOME_VALUE, + SAMPLING_PRIORITY_KEY, samplingPriority != null ? samplingPriority.toString() : null); + // spotless:on ExtractedContext context = (ExtractedContext) extractor.extract(headers, stringValuesMap()); @@ -107,13 +108,16 @@ void extractHttpHeadersWithB3HeaderAtTheBeginning( @ConvertWith(PrioritySamplingConverter.class) byte expectedSamplingPriority) { String traceIdHex = "1"; String spanIdHex = "2"; - Map headers = new LinkedHashMap<>(); - headers.put("", "empty key"); - headers.put(B3_KEY, b3); - headers.put(TRACE_ID_KEY.toUpperCase(), traceIdHex); - headers.put(SPAN_ID_KEY.toUpperCase(), spanIdHex); - headers.put(SOME_HEADER, SOME_VALUE); - headers.put(SAMPLING_PRIORITY_KEY, SAMPLING_PRIORITY_ACCEPT); + // spotless:off + Map headers = headers( + "", "empty key", + B3_KEY, b3, + TRACE_ID_KEY, traceIdHex, + SPAN_ID_KEY, spanIdHex, + SOME_HEADER, SOME_VALUE, + SAMPLING_PRIORITY_KEY, SAMPLING_PRIORITY_ACCEPT + ); + // spotless:on ExtractedContext context = (ExtractedContext) this.extractor.extract(headers, stringValuesMap()); @@ -136,13 +140,16 @@ void extractHttpHeadersWithB3HeaderAtTheEnd( @ConvertWith(PrioritySamplingConverter.class) byte expectedSamplingPriority) { String traceIdHex = "1"; String spanIdHex = "2"; - Map headers = new LinkedHashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceIdHex); - headers.put(SPAN_ID_KEY.toUpperCase(), spanIdHex); - headers.put(B3_KEY, b3); - headers.put(SOME_HEADER, SOME_VALUE); - headers.put(SAMPLING_PRIORITY_KEY, SAMPLING_PRIORITY_ACCEPT); + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceIdHex, + SPAN_ID_KEY, spanIdHex, + B3_KEY, b3, + SOME_HEADER, SOME_VALUE, + SAMPLING_PRIORITY_KEY, SAMPLING_PRIORITY_ACCEPT + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -188,9 +195,12 @@ private Map expectedB3Tags(TagContext context) { }) void extract128BitIdTruncatesIdTo64Bit( String traceId, String spanId, String expectedTraceIdHex, Long expectedSpanId) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -224,11 +234,14 @@ void extractHeaderTagsWithNoPropagation() { @Test void extractHeadersWithForwarding() { String forwarded = "for=" + FORWARDED_IP + ":" + FORWARDED_PORT; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "Forwarded", forwarded + ); + // spotless:on TagContext context = extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -246,14 +259,18 @@ void extractHeadersWithForwarding() { @Test void extractHeadersWithXForwarding() { - Map tagOnlyCtx = new HashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", FORWARDED_IP); - tagOnlyCtx.put("X-Forwarded-Port", FORWARDED_PORT); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("x-forwarded-for", FORWARDED_IP); - fullCtx.put("x-forwarded-port", FORWARDED_PORT); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", FORWARDED_IP, + "X-Forwarded-Port", FORWARDED_PORT + ); + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "x-forwarded-for", FORWARDED_IP, + "x-forwarded-port", FORWARDED_PORT + ); + // spotless:on TagContext context = extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -272,16 +289,18 @@ void extractHeadersWithXForwarding() { @Test void extractEmptyHeadersReturnsNull() { - assertNull( - extractor.extract(singletonMap("ignored-header", "ignored-value"), stringValuesMap())); + assertNull(extractor.extract(headers("ignored-header", "ignored-value"), stringValuesMap())); } @Test void extractHttpHeadersWithInvalidNonNumericId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "traceId"); - headers.put(SPAN_ID_KEY.toUpperCase(), "spanId"); - headers.put(SOME_HEADER, SOME_VALUE); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "traceId", + SPAN_ID_KEY, "spanId", + SOME_HEADER, SOME_VALUE + ); + // spotless:on TagContext context = extractor.extract(headers, stringValuesMap()); @@ -291,10 +310,13 @@ void extractHttpHeadersWithInvalidNonNumericId() { @Test void extractHttpHeadersWithOutOfRangeSpanId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "0"); - headers.put(SPAN_ID_KEY.toUpperCase(), "-1"); - headers.put(SOME_HEADER, SOME_VALUE); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "0", + SPAN_ID_KEY, "-1", + SOME_HEADER, SOME_VALUE + ); + // spotless:on TagContext context = extractor.extract(headers, stringValuesMap()); @@ -314,9 +336,12 @@ void extractHttpHeadersWithOutOfRangeSpanId() { }) void extractIdsWhileRetainingTheOriginalString( String traceId, String spanId, long expectedSpanId) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId + ); + // spotless:on B3TraceId expectedTraceId = B3TraceId.fromHex(traceId); ExtractedContext context = (ExtractedContext) extractor.extract(headers, stringValuesMap()); @@ -341,17 +366,20 @@ private static String trimmed(String hex) { @Test void extractCommonHttpHeaders() { - Map headers = new HashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9" + ); + // spotless:on TagContext context = extractor.extract(headers, stringValuesMap()); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpInjectorTest.java index e47fdcebb88..c3d653498ef 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3HttpInjectorTest.java @@ -1,11 +1,15 @@ package datadog.trace.core.propagation; +import static datadog.trace.api.ConfigDefaults.DEFAULT_PROPAGATION_B3_PADDING_ENABLED; import static datadog.trace.api.sampling.PrioritySampling.UNSET; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; import static datadog.trace.core.propagation.B3HttpCodec.B3_KEY; import static datadog.trace.core.propagation.B3HttpCodec.SAMPLING_PRIORITY_KEY; import static datadog.trace.core.propagation.B3HttpCodec.SPAN_ID_KEY; import static datadog.trace.core.propagation.B3HttpCodec.TRACE_ID_KEY; +import static datadog.trace.core.propagation.B3TestHelper.spanIdOrPadded; +import static datadog.trace.core.propagation.B3TestHelper.traceIdOrPadded; +import static datadog.trace.core.propagation.B3TestHelper.trimHex; import static java.util.Collections.emptyMap; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,7 +32,7 @@ import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; -abstract class B3HttpInjectorTest extends DDCoreJavaSpecification { +class B3HttpInjectorTest extends DDCoreJavaSpecification { private static final CarrierSetter> MAP_SETTER = Map::put; @@ -36,7 +40,9 @@ abstract class B3HttpInjectorTest extends DDCoreJavaSpecification { private HttpCodec.Extractor extractor; private CoreTracer tracer; - protected abstract boolean tracePropagationB3Padding(); + protected boolean tracePropagationB3Padding() { + return DEFAULT_PROPAGATION_B3_PADDING_ENABLED; + } @BeforeEach void setup() { @@ -77,8 +83,8 @@ void injectHttpHeaders( Map carrier = new HashMap<>(); this.injector.inject(spanContext, carrier, MAP_SETTER); - String traceIdHex = idOrPadded(traceId, 32); - String spanIdHex = idOrPadded(spanId, 16); + String traceIdHex = traceIdOrPadded(traceId, tracePropagationB3Padding()); + String spanIdHex = spanIdOrPadded(spanId, tracePropagationB3Padding()); assertEquals(traceIdHex, carrier.get(TRACE_ID_KEY)); assertEquals(spanIdHex, carrier.get(SPAN_ID_KEY)); @@ -113,51 +119,14 @@ void injectHttpHeadersWithExtractedOriginal(String traceId, String spanId) { Map carrier = new HashMap<>(); this.injector.inject(mockedContext, carrier, MAP_SETTER); - String traceIdHex = idOrPadded(traceId, 32); - String spanIdHex = idOrPadded(trimHex(spanId), 16); + String traceIdHex = traceIdOrPadded(traceId, tracePropagationB3Padding()); + String spanIdHex = spanIdOrPadded(trimHex(spanId), tracePropagationB3Padding()); assertEquals(traceIdHex, carrier.get(TRACE_ID_KEY)); assertEquals(spanIdHex, carrier.get(SPAN_ID_KEY)); assertEquals(traceIdHex + "-" + spanIdHex, carrier.get(B3_KEY)); assertEquals(3, carrier.size()); } - private String idOrPadded(long id, int size) { - return idOrPadded(Long.toHexString(id), size); - } - - private String idOrPadded(String id, int size) { - if (!tracePropagationB3Padding()) { - return id.toLowerCase(); - } - return padHexLower(id, size); - } - - private static String padHexLower(String hex, int size) { - String lower = hex.toLowerCase(); - int diff = size - lower.length(); - if (diff <= 0) { - return lower; - } - StringBuilder sb = new StringBuilder(size); - for (int i = 0; i < diff; i++) { - sb.append('0'); - } - sb.append(lower); - return sb.toString(); - } - - private static String trimHex(String hex) { - int length = hex.length(); - int firstNonZero = 0; - while (firstNonZero < length && hex.charAt(firstNonZero) == '0') { - firstNonZero++; - } - if (firstNonZero == length) { - return "0"; - } - return hex.substring(firstNonZero, length); - } - private DDSpanContext mockedSpanContext(TagContext context) { return mockedSpanContext(context.getTraceId(), context.getSpanId(), UNSET); } @@ -194,11 +163,4 @@ protected boolean tracePropagationB3Padding() { return false; } } - - static class B3HttpInjectorPaddedTest extends B3HttpInjectorTest { - @Override - protected boolean tracePropagationB3Padding() { - return true; - } - } } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3TestHelper.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3TestHelper.java new file mode 100644 index 00000000000..f8867c2b1cf --- /dev/null +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/B3TestHelper.java @@ -0,0 +1,72 @@ +package datadog.trace.core.propagation; + +import datadog.trace.api.DDTraceId; + +/** + * This class contains helper methods for formatting trace and span identifiers for B3 propagation + * tests. + */ +public final class B3TestHelper { + + private B3TestHelper() {} + + static String traceIdOrPadded(DDTraceId id, boolean padding) { + if (id.toHighOrderLong() == 0) { + return idOrPadded(Long.toHexString(id.toLong()), 32, padding); + } + return id.toHexString(); + } + + static String traceIdOrPadded(long id, boolean padding) { + return idOrPadded(id, 32, padding); + } + + static String traceIdOrPadded(String hexTraceId, boolean padding) { + return idOrPadded(hexTraceId, 32, padding); + } + + static String spanIdOrPadded(long id, boolean padding) { + return idOrPadded(id, 16, padding); + } + + static String spanIdOrPadded(String hexSpanId, boolean padding) { + return idOrPadded(hexSpanId, 16, padding); + } + + private static String idOrPadded(long id, int size, boolean padding) { + return idOrPadded(Long.toHexString(id), size, padding); + } + + private static String idOrPadded(String id, int size, boolean padding) { + if (!padding) { + return id.toLowerCase(); + } + return padHexLower(id, size); + } + + private static String padHexLower(String hex, int size) { + String lower = hex.toLowerCase(); + int diff = size - lower.length(); + if (diff <= 0) { + return lower; + } + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < diff; i++) { + sb.append('0'); + } + sb.append(lower); + return sb.toString(); + } + + static String trimHex(String hex) { + int length = hex.length(); + int firstNonZero = 0; + while (firstNonZero < length && hex.charAt(firstNonZero) == '0') { + firstNonZero++; + } + if (firstNonZero == length) { + return "0"; + } + return hex.substring(firstNonZero, length); + } +} diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpExtractorTest.java index 5262bebd1b3..fcd680711ff 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpExtractorTest.java @@ -7,14 +7,14 @@ import static datadog.trace.api.sampling.PrioritySampling.UNSET; import static datadog.trace.bootstrap.ActiveSubsystems.APPSEC_ACTIVE; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; -import static datadog.trace.core.CoreTracer.TRACE_ID_MAX; import static datadog.trace.core.propagation.DatadogHttpCodec.DATADOG_TAGS_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.ORIGIN_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX; import static datadog.trace.core.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.SPAN_ID_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.TRACE_ID_KEY; -import static java.math.BigInteger.ONE; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; +import static datadog.trace.junit.utils.tabletest.TraceIdConverter.TRACE_ID_MAX_PLUS_1; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -32,6 +32,7 @@ import datadog.trace.bootstrap.instrumentation.api.TagContext; import datadog.trace.junit.utils.config.WithConfig; import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import datadog.trace.test.util.DDJavaSpecification; import java.util.HashMap; import java.util.Map; @@ -79,32 +80,31 @@ void teardown() { } @TableTest({ - "scenario | traceId | spanId | samplingPriority | origin ", - "unset no origin | '1' | '2' | PrioritySampling.UNSET | ", - "keep with origin | '2' | '3' | PrioritySampling.SAMPLER_KEEP | 'saipan'", - "uint64 max unset | '18446744073709551615' | '18446744073709551614' | PrioritySampling.UNSET | 'saipan'", - "uint64 max-1 keep | '18446744073709551614' | '18446744073709551615' | PrioritySampling.SAMPLER_KEEP | 'saipan'" + "scenario | traceId | spanId | samplingPriority | origin ", + "unset no origin | '1' | '2' | PrioritySampling.UNSET | ", + "keep with origin | '2' | '3' | PrioritySampling.SAMPLER_KEEP | 'saipan'", + "uint64 max unset | 'TRACE_ID_MAX' | 'TRACE_ID_MAX-1' | PrioritySampling.UNSET | 'saipan'", + "uint64 max-1 keep | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX' | PrioritySampling.SAMPLER_KEEP | 'saipan'" }) void extractHttpHeaders( - String traceId, - String spanId, + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String origin) { - Map headers = new HashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info,and-more"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); - if (samplingPriority != UNSET) { - headers.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority)); - } - if (origin != null) { - headers.put(ORIGIN_KEY, origin); - } + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId, + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info,and-more", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2", + SAMPLING_PRIORITY_KEY, samplingPriority != UNSET ? String.valueOf(samplingPriority) : null, + ORIGIN_KEY, origin + ); + // spotless:on ExtractedContext context = (ExtractedContext) extractor.extract(headers, stringValuesMap()); @@ -130,11 +130,14 @@ void extractHttpHeadersWithoutComma() { DynamicConfig.create().setHeaderTags(singletonMap(SOME_HEADER, SOME_TAG)).apply(); this.extractor = DatadogHttpCodec.newExtractor(Config.get(), dynamicConfig::captureTraceConfig); - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "1"); - headers.put(SPAN_ID_KEY.toUpperCase(), "2"); String headerWithComma = "my-interesting-info,and-more"; - headers.put(SOME_HEADER, headerWithComma); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + SOME_HEADER, headerWithComma + ); + // spotless:on ExtractedContext context = (ExtractedContext) this.extractor.extract(headers, stringValuesMap()); @@ -146,11 +149,12 @@ void extractHttpHeadersWithoutComma() { @ParameterizedTest @ValueSource(booleans = {false, true}) void extractHeaderTagsWithNoPropagation(boolean withOrigin) { - Map headers = new HashMap<>(); - if (withOrigin) { - headers.put(ORIGIN_KEY, "my-origin"); - } - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + ORIGIN_KEY, withOrigin ? "my-origin" : null, + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -166,11 +170,14 @@ void extractHeadersWithForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; String forwarded = "for=" + forwardedIp + ":" + forwardedPort; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "Forwarded", forwarded + ); + // spotless:on TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -190,14 +197,18 @@ void extractHeadersWithForwarding() { void extractHeadersWithXForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; - Map tagOnlyCtx = new HashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", forwardedIp); - tagOnlyCtx.put("X-Forwarded-Port", forwardedPort); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("x-forwarded-for", forwardedIp); - fullCtx.put("x-forwarded-port", forwardedPort); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", forwardedIp, + "X-Forwarded-Port", forwardedPort + ); + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "x-forwarded-for", forwardedIp, + "x-forwarded-port", forwardedPort + ); + // spotless:on TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -216,7 +227,7 @@ void extractHeadersWithXForwarding() { @Test void extractEmptyHeadersReturnsNull() { - Map headers = singletonMap("ignored-header", "ignored-value"); + Map headers = headers("ignored-header", "ignored-value"); assertNull(this.extractor.extract(headers, stringValuesMap())); } @@ -273,17 +284,18 @@ void extractHttpHeadersWith128BitTraceId(String hexId) { DD128bTraceId traceId = DD128bTraceId.fromHex(hexId); boolean is128bTrace = traceId.toHighOrderLong() != 0; - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId.toString()); - headers.put(SPAN_ID_KEY.toUpperCase(), "2"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - if (is128bTrace) { - headers.put( - DATADOG_TAGS_KEY.toUpperCase(), - "_dd.p.tid=" + LongStringUtils.toHexStringPadded(traceId.toHighOrderLong(), 16)); - } + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId.toString(), + SPAN_ID_KEY, "2", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info", + DATADOG_TAGS_KEY, is128bTrace + ? "_dd.p.tid=" + LongStringUtils.toHexStringPadded(traceId.toHighOrderLong(), 16) + : null + ); + // spotless:on ExtractedContext context = (ExtractedContext) this.extractor.extract(headers, stringValuesMap()); @@ -300,12 +312,15 @@ void extractHttpHeadersWith128BitTraceId(String hexId) { @Test void extractHttpHeadersWithInvalidNonNumericId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "traceId"); - headers.put(SPAN_ID_KEY.toUpperCase(), "spanId"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "traceId", + SPAN_ID_KEY, "spanId", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -314,13 +329,15 @@ void extractHttpHeadersWithInvalidNonNumericId() { @Test void extractHttpHeadersWithOutOfRangeTraceId() { - String outOfRangeTraceId = TRACE_ID_MAX.add(ONE).toString(); - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), outOfRangeTraceId); - headers.put(SPAN_ID_KEY.toUpperCase(), "0"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, TRACE_ID_MAX_PLUS_1, + SPAN_ID_KEY, "0", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -329,12 +346,15 @@ void extractHttpHeadersWithOutOfRangeTraceId() { @Test void extractHttpHeadersWithOutOfRangeSpanId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "0"); - headers.put(SPAN_ID_KEY.toUpperCase(), "-1"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "0", + SPAN_ID_KEY, "-1", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -342,20 +362,26 @@ void extractHttpHeadersWithOutOfRangeSpanId() { } @TableTest({ - "scenario | traceId | spanId | expectExtraction", - "negative traceId | '-1' | '1' | false ", - "negative spanId | '1' | '-1' | false ", - "zero traceId | '0' | '1' | false ", - "zero spanId | '1' | '0' | true ", - "uint64 max traceId | '18446744073709551615' | '1' | true ", - "out-of-range traceId | '18446744073709551616' | '1' | false ", - "uint64 max spanId | '1' | '18446744073709551615' | true ", - "out-of-range spanId | '1' | '18446744073709551616' | false " + "scenario | traceId | spanId | expectExtraction", + "negative traceId | '-1' | '1' | false ", + "negative spanId | '1' | '-1' | false ", + "zero traceId | '0' | '1' | false ", + "zero spanId | '1' | '0' | true ", + "uint64 max traceId | 'TRACE_ID_MAX' | '1' | true ", + "out-of-range traceId | 'TRACE_ID_MAX+1' | '1' | false ", + "uint64 max spanId | '1' | 'TRACE_ID_MAX' | true ", + "out-of-range spanId | '1' | 'TRACE_ID_MAX+1' | false " }) - void moreIdRangeValidation(String traceId, String spanId, boolean expectExtraction) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); + void moreIdRangeValidation( + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, + boolean expectExtraction) { + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -374,16 +400,19 @@ void moreIdRangeValidation(String traceId, String spanId, boolean expectExtracti "epoch 2021 | '2' | '3' | 1610001234 " }) void extractHttpHeadersWithEndToEnd(String traceId, String spanId, long endToEndStartTime) { - Map headers = new HashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "t0").toUpperCase(), String.valueOf(endToEndStartTime)); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId, + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "t0", String.valueOf(endToEndStartTime), + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on ExtractedContext context = (ExtractedContext) this.extractor.extract(headers, stringValuesMap()); @@ -401,20 +430,26 @@ void extractHttpHeadersWithEndToEnd(String traceId, String spanId, long endToEnd } @TableTest({ - "scenario | traceId | spanId | ctxCreated", - "negative traceId | '-1' | '1' | false ", - "negative spanId | '1' | '-1' | false ", - "zero traceId | '0' | '1' | true ", - "uint64 max-1 ids | '18446744073709551614' | '18446744073709551614' | true " + "scenario | traceId | spanId | ctxCreated", + "negative traceId | '-1' | '1' | false ", + "negative spanId | '1' | '-1' | false ", + "zero traceId | '0' | '1' | true ", + "uint64 max-1 ids | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX-1' | true " }) - void baggageIsMappedOnContextCreation(String traceId, String spanId, boolean ctxCreated) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_ARBITRARY_HEADER, "my-interesting-info"); + void baggageIsMappedOnContextCreation( + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, + boolean ctxCreated) { + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId, + SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_ARBITRARY_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -432,17 +467,20 @@ void baggageIsMappedOnContextCreation(String traceId, String spanId, boolean ctx @Test void extractCommonHttpHeaders() { - Map headers = new HashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpInjectorTest.java index 1369bc5fd82..b76f8f810d1 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/DatadogHttpInjectorTest.java @@ -23,6 +23,7 @@ import datadog.trace.core.DDCoreJavaSpecification; import datadog.trace.core.DDSpanContext; import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.AfterEach; @@ -50,15 +51,15 @@ void tearDown() { } @TableTest({ - "scenario | traceId | spanId | samplingPriority | origin ", - "unset no origin | '1' | '2' | PrioritySampling.UNSET | ", - "keep with origin | '1' | '2' | PrioritySampling.SAMPLER_KEEP | 'saipan'", - "uint64 max unset | '18446744073709551615' | '18446744073709551614' | PrioritySampling.UNSET | 'saipan'", - "uint64 max-1 keep | '18446744073709551614' | '18446744073709551615' | PrioritySampling.SAMPLER_KEEP | " + "scenario | traceId | spanId | samplingPriority | origin ", + "unset no origin | '1' | '2' | PrioritySampling.UNSET | ", + "keep with origin | '1' | '2' | PrioritySampling.SAMPLER_KEEP | 'saipan'", + "uint64 max unset | 'TRACE_ID_MAX' | 'TRACE_ID_MAX-1' | PrioritySampling.UNSET | 'saipan'", + "uint64 max-1 keep | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX' | PrioritySampling.SAMPLER_KEEP | " }) void injectHttpHeaders( - String traceId, - String spanId, + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String origin) { Map baggage = new HashMap<>(); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpExtractorTest.java index 524ca59fa61..59e9d9dfb66 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpExtractorTest.java @@ -4,13 +4,13 @@ import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; import static datadog.trace.bootstrap.ActiveSubsystems.APPSEC_ACTIVE; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; -import static datadog.trace.core.CoreTracer.TRACE_ID_MAX; import static datadog.trace.core.propagation.HaystackHttpCodec.HAYSTACK_SPAN_ID_BAGGAGE_KEY; import static datadog.trace.core.propagation.HaystackHttpCodec.HAYSTACK_TRACE_ID_BAGGAGE_KEY; import static datadog.trace.core.propagation.HaystackHttpCodec.OT_BAGGAGE_PREFIX; import static datadog.trace.core.propagation.HaystackHttpCodec.SPAN_ID_KEY; import static datadog.trace.core.propagation.HaystackHttpCodec.TRACE_ID_KEY; -import static java.math.BigInteger.ONE; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; +import static datadog.trace.junit.utils.tabletest.TraceIdConverter.TRACE_ID_MAX_MINUS_1; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -24,12 +24,14 @@ import datadog.trace.api.DynamicConfig; import datadog.trace.bootstrap.instrumentation.api.TagContext; import datadog.trace.junit.utils.config.WithConfig; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import datadog.trace.test.util.DDJavaSpecification; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; @WithConfig(key = PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED, value = "true") @@ -70,23 +72,30 @@ void teardown() { } @TableTest({ - "scenario | traceId | spanId | traceUuid | spanUuid ", - "small ids | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", - "incrementing ids | '2' | '3' | '44617461-646f-6721-0000-000000000002' | '44617461-646f-6721-0000-000000000003'", - "uint64 max | '18446744073709551615' | '18446744073709551609' | '44617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffff9'", - "uint64 max-1 | '18446744073709551614' | '18446744073709551608' | '44617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-fffffffffff8'" + "scenario | traceId | spanId | traceUuid | spanUuid ", + "small ids | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", + "incrementing ids | '2' | '3' | '44617461-646f-6721-0000-000000000002' | '44617461-646f-6721-0000-000000000003'", + "uint64 max | 'TRACE_ID_MAX' | '18446744073709551609' | '44617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffff9'", + "uint64 max-1 | 'TRACE_ID_MAX-1' | '18446744073709551608' | '44617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-fffffffffff8'" }) - void extractHttpHeaders(String traceId, String spanId, String traceUuid, String spanUuid) { - Map headers = new HashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceUuid); - headers.put(SPAN_ID_KEY.toUpperCase(), spanUuid); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "%76%32"); // v2 encoded once - headers.put((OT_BAGGAGE_PREFIX + "k3").toUpperCase(), "%25%37%36%25%33%33"); // v3 encoded twice - headers.put(SOME_HEADER, "my-interesting-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); + void extractHttpHeaders( + @ConvertWith(TraceIdConverter.class) String traceId, + String spanId, + String traceUuid, + String spanUuid) { + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceUuid, + SPAN_ID_KEY, spanUuid, + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "%76%32", // v2 encoded once + OT_BAGGAGE_PREFIX + "k3", "%25%37%36%25%33%33", // v3 encoded twice + SOME_HEADER, "my-interesting-info", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on ExtractedContext context = (ExtractedContext) this.extractor.extract(headers, stringValuesMap()); @@ -109,7 +118,7 @@ void extractHttpHeaders(String traceId, String spanId, String traceUuid, String @Test void extractHeaderTagsWithNoPropagation() { - Map headers = singletonMap(SOME_HEADER, "my-interesting-info"); + Map headers = headers(SOME_HEADER, "my-interesting-info"); TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -122,11 +131,14 @@ void extractHeadersWithForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "123"; String forwarded = "for=" + forwardedIp + ":" + forwardedPort; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "Forwarded", forwarded + ); + // spotless:on TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -146,14 +158,18 @@ void extractHeadersWithForwarding() { void extractHeadersWithXForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "123"; - Map tagOnlyCtx = new HashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", forwardedIp); - tagOnlyCtx.put("X-Forwarded-Port", forwardedPort); - Map fullCtx = new HashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("x-forwarded-for", forwardedIp); - fullCtx.put("x-forwarded-port", forwardedPort); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", forwardedIp, + "X-Forwarded-Port", forwardedPort + ); + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "x-forwarded-for", forwardedIp, + "x-forwarded-port", forwardedPort + ); + // spotless:on TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -178,12 +194,15 @@ void extractEmptyHeadersReturnsNull() { @Test void extractHttpHeadersWithInvalidNonNumericId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "traceId"); - headers.put(SPAN_ID_KEY.toUpperCase(), "spanId"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "traceId", + SPAN_ID_KEY, "spanId", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -192,13 +211,15 @@ void extractHttpHeadersWithInvalidNonNumericId() { @Test void extractHttpHeadersWithOutOfRangeTraceId() { - String outOfRangeTraceId = TRACE_ID_MAX.add(ONE).toString(); - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), outOfRangeTraceId); - headers.put(SPAN_ID_KEY.toUpperCase(), "0"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, TRACE_ID_MAX_MINUS_1, + SPAN_ID_KEY, "0", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -207,12 +228,15 @@ void extractHttpHeadersWithOutOfRangeTraceId() { @Test void extractHttpHeadersWithOutOfRangeSpanId() { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "0"); - headers.put(SPAN_ID_KEY.toUpperCase(), "-1"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "0", + SPAN_ID_KEY, "-1", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -227,13 +251,16 @@ void extractHttpHeadersWithOutOfRangeSpanId() { "uuid format | '44617461-646f-6721-463a-c35c9f6413ad' | '44617461-646f-6721-463a-c35c9f6413ad' | true " }) void baggageIsMappedOnContextCreation(String traceId, String spanId, boolean ctxCreated) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_ARBITRARY_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId, + SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_ARBITRARY_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -274,9 +301,11 @@ void extract128BitIdTruncatesIdTo64Bit( Long expectedTraceIdLong, long expectedSpanId, boolean ctxCreated) { - Map headers = new HashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); @@ -293,17 +322,20 @@ void extract128BitIdTruncatesIdTo64Bit( @Test void extractCommonHttpHeaders() { - Map headers = new HashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9" + ); + // spotless:on TagContext context = this.extractor.extract(headers, stringValuesMap()); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpInjectorTest.java index 7e5b02e76f5..e8b5f1151fe 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HaystackHttpInjectorTest.java @@ -19,10 +19,12 @@ import datadog.trace.core.CoreTracer; import datadog.trace.core.DDCoreJavaSpecification; import datadog.trace.core.DDSpanContext; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; class HaystackHttpInjectorTest extends DDCoreJavaSpecification { @@ -47,13 +49,17 @@ void tearDown() { } @TableTest({ - "scenario | traceId | spanId | traceUuid | spanUuid ", - "small ids | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", - "small ids duplicate | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", - "uint64 max trace | '18446744073709551615' | '18446744073709551614' | '44617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffffe'", - "uint64 max-1 trace | '18446744073709551614' | '18446744073709551615' | '44617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-ffffffffffff'" + "scenario | traceId | spanId | traceUuid | spanUuid ", + "small ids | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", + "small ids duplicate | '1' | '2' | '44617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", + "uint64 max trace | 'TRACE_ID_MAX' | 'TRACE_ID_MAX-1' | '44617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffffe'", + "uint64 max-1 trace | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX' | '44617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-ffffffffffff'" }) - void injectHttpHeaders(String traceId, String spanId, String traceUuid, String spanUuid) { + void injectHttpHeaders( + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, + String traceUuid, + String spanUuid) { Map baggage = new HashMap<>(); baggage.put("k1", "v1"); baggage.put("k2", "v2"); @@ -77,14 +83,17 @@ void injectHttpHeaders(String traceId, String spanId, String traceUuid, String s } @TableTest({ - "scenario | traceId | spanId | traceUuid | spanUuid ", - "small ids | '1' | '2' | '54617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", - "small ids duplicate | '1' | '2' | '54617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", - "uint64 max trace | '18446744073709551615' | '18446744073709551614' | '54617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffffe'", - "uint64 max-1 trace | '18446744073709551614' | '18446744073709551615' | '54617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-ffffffffffff'" + "scenario | traceId | spanId | traceUuid | spanUuid ", + "small ids | '1' | '2' | '54617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", + "small ids duplicate | '1' | '2' | '54617461-646f-6721-0000-000000000001' | '44617461-646f-6721-0000-000000000002'", + "uint64 max trace | 'TRACE_ID_MAX' | 'TRACE_ID_MAX-1' | '54617461-646f-6721-ffff-ffffffffffff' | '44617461-646f-6721-ffff-fffffffffffe'", + "uint64 max-1 trace | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX' | '54617461-646f-6721-ffff-fffffffffffe' | '44617461-646f-6721-ffff-ffffffffffff'" }) void injectHttpHeadersWithHaystackTraceIdInBaggage( - String traceId, String spanId, String traceUuid, String spanUuid) { + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, + String traceUuid, + String spanUuid) { Map baggage = new HashMap<>(); baggage.put("k1", "v1"); baggage.put("k2", "v2"); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpCodecTestHelper.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpCodecTestHelper.java index 00e0d460572..a109c935cf7 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpCodecTestHelper.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpCodecTestHelper.java @@ -2,6 +2,8 @@ import datadog.trace.api.Config; import datadog.trace.api.TraceConfig; +import java.util.HashMap; +import java.util.Map; import java.util.function.Supplier; /** Helper class used only for tests to bridge package-private classes */ @@ -14,4 +16,17 @@ public static HttpCodec.Extractor newW3cHttpCodecExtractor( Config config, Supplier traceConfigSupplier) { return W3CHttpCodec.newExtractor(config, traceConfigSupplier); } + + static Map headers(String... headerKeysAndValues) { + HashMap headers = new HashMap<>(); + for (int i = 0; i < headerKeysAndValues.length / 2; i++) { + String headerValue = headerKeysAndValues[i * 2 + 1]; + if (headerValue == null) { + continue; + } + String headerName = headerKeysAndValues[i * 2].toUpperCase(); + headers.put(headerName, headerValue); + } + return headers; + } } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpExtractorTest.java index 28126cb724b..eb9727cc4a7 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpExtractorTest.java @@ -5,6 +5,7 @@ import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; import static datadog.trace.core.propagation.B3HttpCodec.B3_SPAN_ID; import static datadog.trace.core.propagation.B3HttpCodec.B3_TRACE_ID; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -22,60 +23,55 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; import datadog.trace.bootstrap.instrumentation.api.TagContext; import datadog.trace.test.util.DDJavaSpecification; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; +import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; import org.tabletest.junit.TypeConverter; -public class HttpExtractorTest extends DDJavaSpecification { +class HttpExtractorTest extends DDJavaSpecification { private static final String W3C_TRACE_ID = "00000000000000000000000000000001"; private static final String W3C_SPAN_ID = "123456789abcdef0"; private static final String W3C_TRACE_PARENT = "00-" + W3C_TRACE_ID + "-" + W3C_SPAN_ID + "-01"; - private static final String W3C_TRACE_STATE_WITH_P = "dd=p:456789abcdef0123"; + private static final String W3C_PARENT_ID = "456789abcdef0123"; + private static final String W3C_TRACE_STATE_WITH_P = "dd=p:" + W3C_PARENT_ID; private static final String W3C_TRACE_STATE_NO_P = "dd=s:2,foo=1"; private static final String W3C_SPAN_ID_LSTR = Long.toString(DDSpanId.fromHex(W3C_SPAN_ID)); - @TypeConverter - public static TracePropagationStyle parseTracePropagationStyle(String value) { - String name = value.trim(); - if (name.startsWith("TracePropagationStyle.")) { - name = name.substring("TracePropagationStyle.".length()); - } - return TracePropagationStyle.valueOf(name); - } - @TableTest({ - "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | w3cTraceParent | expectedTraceId | expectedSpanId | putDatadogFields | expectDatadogFields | tagContext | extractFirst", - "DATADOG,B3MULTI ids | [DATADOG, B3MULTI] | '1' | '2' | 'a' | 'b' | | '1' | '2' | true | true | false | false ", - "DATADOG,B3MULTI b3 only | [DATADOG, B3MULTI] | | | 'a' | 'b' | | '10' | '11' | false | false | true | false ", - "DATADOG,B3MULTI b3 only with dd field | [DATADOG, B3MULTI] | | | 'a' | 'b' | | | | true | true | true | false ", - "DATADOG only | [DATADOG] | '1' | '2' | 'a' | 'b' | | '1' | '2' | true | true | false | false ", - "B3MULTI only | [B3MULTI] | '1' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", - "B3MULTI,DATADOG | [B3MULTI, DATADOG] | '1' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", - "no styles | [] | '1' | '2' | 'a' | 'b' | | | | false | false | false | false ", - "DATADOG,B3MULTI invalid datadog trace | [DATADOG, B3MULTI] | 'abc' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", - "DATADOG only invalid trace | [DATADOG] | 'abc' | '2' | 'a' | 'b' | | | | false | false | false | false ", - "DATADOG,B3MULTI dd trace out of range | [DATADOG, B3MULTI] | '18446744073709551616' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", - "DATADOG,B3MULTI dd span out of range | [DATADOG, B3MULTI] | '1' | '18446744073709551616' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", - "DATADOG only dd trace out of range | [DATADOG] | '18446744073709551616' | '2' | 'a' | 'b' | | | | false | false | false | false ", - "DATADOG only dd span out of range | [DATADOG] | '1' | '18446744073709551616' | 'a' | 'b' | | | | false | false | false | false ", - "DATADOG,B3MULTI b3 trace out of range | [DATADOG, B3MULTI] | '1' | '2' | '18446744073709551616' | 'b' | | '1' | '2' | true | false | false | false ", - "DATADOG,B3MULTI b3 span out of range | [DATADOG, B3MULTI] | '1' | '2' | 'a' | '18446744073709551616' | | '1' | '2' | true | false | false | false ", - "NONE | [NONE] | '1' | '2' | | | | | | true | false | true | false ", - "DATADOG,TRACECONTEXT w3c override | [DATADOG, TRACECONTEXT] | '1' | '2' | | | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "DATADOG,TRACECONTEXT,B3MULTI w3c override | [DATADOG, TRACECONTEXT, B3MULTI] | '1' | '2' | '1' | '2' | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "TRACECONTEXT,DATADOG | [TRACECONTEXT, DATADOG] | '1' | '2' | | | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "TRACECONTEXT,B3MULTI | [TRACECONTEXT, B3MULTI] | | | '1' | '2' | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "TRACECONTEXT,B3MULTI,DATADOG | [TRACECONTEXT, B3MULTI, DATADOG] | '1' | '2' | '1' | '4' | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "B3MULTI,DATADOG,TRACECONTEXT | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "TRACECONTEXT only | [TRACECONTEXT] | | | | | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "DATADOG,TRACECONTEXT no dd span | [DATADOG, TRACECONTEXT] | '1' | | | | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '1311768467463790320' | false | false | false | false ", - "DATADOG,TRACECONTEXT extract first | [DATADOG, TRACECONTEXT] | '1' | '2' | | | '00-00000000000000000000000000000001-123456789abcdef0-01' | '1' | '2' | false | false | false | true " + "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | w3cTraceParent | expectedTraceId | expectedSpanId | putDatadogFields | expectDatadogFields | tagContext | extractFirst", + "DATADOG,B3MULTI ids | [DATADOG, B3MULTI] | '1' | '2' | 'a' | 'b' | | '1' | '2' | true | true | false | false ", + "DATADOG,B3MULTI b3 only | [DATADOG, B3MULTI] | | | 'a' | 'b' | | '10' | '11' | false | false | true | false ", + "DATADOG,B3MULTI b3 only with dd field | [DATADOG, B3MULTI] | | | 'a' | 'b' | | | | true | true | true | false ", + "DATADOG only | [DATADOG] | '1' | '2' | 'a' | 'b' | | '1' | '2' | true | true | false | false ", + "B3MULTI only | [B3MULTI] | '1' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", + "B3MULTI,DATADOG | [B3MULTI, DATADOG] | '1' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", + "no styles | [] | '1' | '2' | 'a' | 'b' | | | | false | false | false | false ", + "DATADOG,B3MULTI invalid datadog trace | [DATADOG, B3MULTI] | 'abc' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", + "DATADOG only invalid trace | [DATADOG] | 'abc' | '2' | 'a' | 'b' | | | | false | false | false | false ", + "DATADOG,B3MULTI dd trace out of range | [DATADOG, B3MULTI] | '18446744073709551616' | '2' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", + "DATADOG,B3MULTI dd span out of range | [DATADOG, B3MULTI] | '1' | '18446744073709551616' | 'a' | 'b' | | '10' | '11' | false | false | false | false ", + "DATADOG only dd trace out of range | [DATADOG] | '18446744073709551616' | '2' | 'a' | 'b' | | | | false | false | false | false ", + "DATADOG only dd span out of range | [DATADOG] | '1' | '18446744073709551616' | 'a' | 'b' | | | | false | false | false | false ", + "DATADOG,B3MULTI b3 trace out of range | [DATADOG, B3MULTI] | '1' | '2' | '18446744073709551616' | 'b' | | '1' | '2' | true | false | false | false ", + "DATADOG,B3MULTI b3 span out of range | [DATADOG, B3MULTI] | '1' | '2' | 'a' | '18446744073709551616' | | '1' | '2' | true | false | false | false ", + "NONE | [NONE] | '1' | '2' | | | | | | true | false | true | false ", + "DATADOG,TRACECONTEXT w3c override | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "DATADOG,TRACECONTEXT,B3MULTI w3c override | [DATADOG, TRACECONTEXT, B3MULTI] | '1' | '2' | '1' | '2' | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "TRACECONTEXT,DATADOG | [TRACECONTEXT, DATADOG] | '1' | '2' | | | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "TRACECONTEXT,B3MULTI | [TRACECONTEXT, B3MULTI] | | | '1' | '2' | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "TRACECONTEXT,B3MULTI,DATADOG | [TRACECONTEXT, B3MULTI, DATADOG] | '1' | '2' | '1' | '4' | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "B3MULTI,DATADOG,TRACECONTEXT | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "TRACECONTEXT only | [TRACECONTEXT] | | | | | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "DATADOG,TRACECONTEXT no dd span | [DATADOG, TRACECONTEXT] | '1' | | | | 'W3C_TRACE_PARENT' | '1' | 'W3C_SPAN_ID_LSTR' | false | false | false | false ", + "DATADOG,TRACECONTEXT extract first | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'W3C_TRACE_PARENT' | '1' | '2' | false | false | false | true " }) void extractHttpHeadersUsingStyles( List styles, @@ -83,23 +79,15 @@ void extractHttpHeadersUsingStyles( String datadogSpanId, String b3TraceId, String b3SpanId, - String w3cTraceParent, + @ConvertWith(W3cConstantConverter.class) String w3cTraceParent, String expectedTraceId, - String expectedSpanId, + @ConvertWith(W3cConstantConverter.class) String expectedSpanId, boolean putDatadogFields, boolean expectDatadogFields, boolean tagContext, boolean extractFirst) { - Config config = mock(Config.class); - when(config.getTracePropagationStylesToExtract()).thenReturn(orderedSetOf(styles)); - when(config.isTracePropagationExtractFirst()).thenReturn(extractFirst); - DynamicConfig dynamicConfig = - DynamicConfig.create() - .setHeaderTags(singletonMap("SOME_HEADER", "some-tag")) - .setBaggageMapping(emptyMap()) - .apply(); HttpCodec.Extractor extractor = - HttpCodec.createExtractor(config, dynamicConfig::captureTraceConfig); + createExtractor(styles, extractFirst, singletonMap("SOME_HEADER", "some-tag")); // spotless:off Map headers = headers( @@ -137,18 +125,18 @@ void extractHttpHeadersUsingStyles( } @TableTest({ - "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | traceState | expectedTraceId | expectedSpanId | expectedParentId ", - "DATADOG,TRACECONTEXT with traceState p | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | '456789abcdef0123'", - "DATADOG,TRACECONTEXT no traceState | [DATADOG, TRACECONTEXT] | '1' | '2' | | | | '1' | '1311768467463790320' | '0000000000000002'", - "DATADOG,TRACECONTEXT,B3MULTI with traceState p | [DATADOG, TRACECONTEXT, B3MULTI] | '1' | '2' | '1' | '2' | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | '456789abcdef0123'", - "TRACECONTEXT,DATADOG with traceState p | [TRACECONTEXT, DATADOG] | '1' | '2' | | | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | ", - "TRACECONTEXT,B3MULTI with traceState p | [TRACECONTEXT, B3MULTI] | | | '1' | '2' | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | ", - "TRACECONTEXT,B3MULTI,DATADOG with traceState p | [TRACECONTEXT, B3MULTI, DATADOG] | '1' | '2' | '1' | '4' | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | ", - "B3MULTI,DATADOG,TRACECONTEXT with traceState p | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | '456789abcdef0123'", - "TRACECONTEXT only with traceState p | [TRACECONTEXT] | | | | | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | ", - "B3MULTI,TRACECONTEXT with traceState p | [B3MULTI, TRACECONTEXT] | | | '1' | '2' | 'dd=p:456789abcdef0123' | '1' | '1311768467463790320' | '456789abcdef0123'", - "B3MULTI,DATADOG,TRACECONTEXT no traceState | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | | '1' | '1311768467463790320' | '0000000000000002'", - "DATADOG,TRACECONTEXT no p traceState | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'dd=s:2,foo=1' | '1' | '1311768467463790320' | '0000000000000002'" + "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | traceState | expectedTraceId | expectedSpanId | expectedParentId ", + "DATADOG,TRACECONTEXT with traceState p | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | 'W3C_PARENT_ID' ", + "DATADOG,TRACECONTEXT no traceState | [DATADOG, TRACECONTEXT] | '1' | '2' | | | | '1' | 'W3C_SPAN_ID_LSTR' | '0000000000000002'", + "DATADOG,TRACECONTEXT,B3MULTI with traceState p | [DATADOG, TRACECONTEXT, B3MULTI] | '1' | '2' | '1' | '2' | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | 'W3C_PARENT_ID' ", + "TRACECONTEXT,DATADOG with traceState p | [TRACECONTEXT, DATADOG] | '1' | '2' | | | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | ", + "TRACECONTEXT,B3MULTI with traceState p | [TRACECONTEXT, B3MULTI] | | | '1' | '2' | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | ", + "TRACECONTEXT,B3MULTI,DATADOG with traceState p | [TRACECONTEXT, B3MULTI, DATADOG] | '1' | '2' | '1' | '4' | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | ", + "B3MULTI,DATADOG,TRACECONTEXT with traceState p | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | 'W3C_PARENT_ID' ", + "TRACECONTEXT only with traceState p | [TRACECONTEXT] | | | | | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | ", + "B3MULTI,TRACECONTEXT with traceState p | [B3MULTI, TRACECONTEXT] | | | '1' | '2' | 'W3C_TRACE_STATE_WITH_P' | '1' | 'W3C_SPAN_ID_LSTR' | 'W3C_PARENT_ID' ", + "B3MULTI,DATADOG,TRACECONTEXT no traceState | [B3MULTI, DATADOG, TRACECONTEXT] | '1' | '2' | '1' | '4' | | '1' | 'W3C_SPAN_ID_LSTR' | '0000000000000002'", + "DATADOG,TRACECONTEXT no p traceState | [DATADOG, TRACECONTEXT] | '1' | '2' | | | 'W3C_TRACE_STATE_NO_P' | '1' | 'W3C_SPAN_ID_LSTR' | '0000000000000002'" }) void checkW3CTraceContextOverride( List styles, @@ -156,15 +144,11 @@ void checkW3CTraceContextOverride( String datadogSpanId, String b3TraceId, String b3SpanId, - String traceState, + @ConvertWith(W3cConstantConverter.class) String traceState, String expectedTraceId, - String expectedSpanId, - String expectedParentId) { - Config config = mock(Config.class); - when(config.getTracePropagationStylesToExtract()).thenReturn(orderedSetOf(styles)); - DynamicConfig dynamicConfig = DynamicConfig.create().apply(); - HttpCodec.Extractor extractor = - HttpCodec.createExtractor(config, dynamicConfig::captureTraceConfig); + @ConvertWith(W3cConstantConverter.class) String expectedSpanId, + @ConvertWith(W3cConstantConverter.class) String expectedParentId) { + HttpCodec.Extractor extractor = createExtractor(styles); // spotless:off Map headers = headers( @@ -186,11 +170,11 @@ void checkW3CTraceContextOverride( } @TableTest({ - "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | w3cTraceParent | traceState | expectedSpanLinks ", - "matching trace IDs no links | [DATADOG, B3MULTI, TRACECONTEXT] | '1' | '2' | '1' | 'b' | '00-00000000000000000000000000000001-123456789abcdef0-01' | 'dd=s:2,foo=1' | [] ", - "only tracecontext mismatch | [DATADOG, B3MULTI, TRACECONTEXT] | '2' | '2' | '2' | 'b' | '00-00000000000000000000000000000001-123456789abcdef0-01' | 'dd=s:2,foo=1' | [TRACECONTEXT] ", - "b3 and tracecontext mismatch | [DATADOG, B3MULTI, TRACECONTEXT] | '2' | '2' | '1' | 'b' | '00-00000000000000000000000000000001-123456789abcdef0-01' | 'dd=s:2,foo=1' | [B3MULTI, TRACECONTEXT]", - "datadog mismatch from tracecontext | [TRACECONTEXT, B3MULTI, DATADOG] | '2' | '2' | '1' | 'b' | '00-00000000000000000000000000000001-123456789abcdef0-01' | 'dd=s:2,foo=1' | [DATADOG] " + "scenario | styles | datadogTraceId | datadogSpanId | b3TraceId | b3SpanId | w3cTraceParent | traceState | expectedSpanLinks ", + "matching trace IDs no links | [DATADOG, B3MULTI, TRACECONTEXT] | '1' | '2' | '1' | 'b' | 'W3C_TRACE_PARENT' | 'W3C_TRACE_STATE_NO_P' | [] ", + "only tracecontext mismatch | [DATADOG, B3MULTI, TRACECONTEXT] | '2' | '2' | '2' | 'b' | 'W3C_TRACE_PARENT' | 'W3C_TRACE_STATE_NO_P' | [TRACECONTEXT] ", + "b3 and tracecontext mismatch | [DATADOG, B3MULTI, TRACECONTEXT] | '2' | '2' | '1' | 'b' | 'W3C_TRACE_PARENT' | 'W3C_TRACE_STATE_NO_P' | [B3MULTI, TRACECONTEXT]", + "datadog mismatch from tracecontext | [TRACECONTEXT, B3MULTI, DATADOG] | '2' | '2' | '1' | 'b' | 'W3C_TRACE_PARENT' | 'W3C_TRACE_STATE_NO_P' | [DATADOG] " }) void verifyExistenceOfSpanLinks( List styles, @@ -198,14 +182,10 @@ void verifyExistenceOfSpanLinks( String datadogSpanId, String b3TraceId, String b3SpanId, - String w3cTraceParent, - String traceState, + @ConvertWith(W3cConstantConverter.class) String w3cTraceParent, + @ConvertWith(W3cConstantConverter.class) String traceState, List expectedSpanLinks) { - Config config = mock(Config.class); - when(config.getTracePropagationStylesToExtract()).thenReturn(orderedSetOf(styles)); - DynamicConfig dynamicConfig = DynamicConfig.create().apply(); - HttpCodec.Extractor extractor = - HttpCodec.createExtractor(config, dynamicConfig::captureTraceConfig); + HttpCodec.Extractor extractor = createExtractor(styles); // spotless:off Map headers = headers( @@ -235,16 +215,50 @@ private static Set orderedSetOf(List(styles); } - private static Map headers(String... headerKeysAndValues) { - HashMap headers = new HashMap<>(); - for (int i = 0; i < headerKeysAndValues.length / 2; i++) { - String headerValue = headerKeysAndValues[i * 2 + 1]; - if (headerValue == null) { - continue; + private static HttpCodec.Extractor createExtractor(List styles) { + return createExtractor(styles, false, emptyMap()); + } + + private static HttpCodec.Extractor createExtractor( + List styles, boolean extractFirst, Map headerTags) { + Config config = mock(Config.class); + when(config.getTracePropagationStylesToExtract()).thenReturn(orderedSetOf(styles)); + when(config.isTracePropagationExtractFirst()).thenReturn(extractFirst); + DynamicConfig dynamicConfig = + DynamicConfig.create().setHeaderTags(headerTags).setBaggageMapping(emptyMap()).apply(); + return HttpCodec.createExtractor(config, dynamicConfig::captureTraceConfig); + } + + @TypeConverter + static TracePropagationStyle parseTracePropagationStyle(String value) { + String name = value.trim(); + if (name.startsWith("TracePropagationStyle.")) { + name = name.substring("TracePropagationStyle.".length()); + } + return TracePropagationStyle.valueOf(name); + } + + static class W3cConstantConverter implements ArgumentConverter { + @Override + public Object convert(Object source, ParameterContext context) + throws ArgumentConversionException { + if (source == null) { + return null; + } + switch (source.toString()) { + case "W3C_TRACE_PARENT": + return W3C_TRACE_PARENT; + case "W3C_TRACE_STATE_WITH_P": + return W3C_TRACE_STATE_WITH_P; + case "W3C_TRACE_STATE_NO_P": + return W3C_TRACE_STATE_NO_P; + case "W3C_SPAN_ID_LSTR": + return W3C_SPAN_ID_LSTR; + case "W3C_PARENT_ID": + return W3C_PARENT_ID; + default: + return source; } - String headerName = headerKeysAndValues[i * 2].toUpperCase(); - headers.put(headerName, headerValue); } - return headers; } } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorB3PaddingTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorB3PaddingTest.java index d041401e2d5..c65fc25cfa6 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorB3PaddingTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorB3PaddingTest.java @@ -1,6 +1,6 @@ package datadog.trace.core.propagation; -public class HttpInjectorB3PaddingTest extends HttpInjectorTest { +class HttpInjectorB3PaddingTest extends HttpInjectorTest { @Override protected boolean tracePropagationB3Padding() { return true; diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorTest.java index 2bed3a09032..abd959426e3 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/HttpInjectorTest.java @@ -1,11 +1,17 @@ package datadog.trace.core.propagation; +import static datadog.trace.api.ConfigDefaults.DEFAULT_PROPAGATION_B3_PADDING_ENABLED; import static datadog.trace.api.sampling.PrioritySampling.UNSET; import static datadog.trace.core.propagation.B3HttpCodec.B3_KEY; import static datadog.trace.core.propagation.B3HttpCodec.SAMPLING_PRIORITY_KEY; +import static datadog.trace.core.propagation.B3TestHelper.spanIdOrPadded; +import static datadog.trace.core.propagation.B3TestHelper.traceIdOrPadded; +import static datadog.trace.core.propagation.DatadogHttpCodec.DATADOG_TAGS_KEY; +import static datadog.trace.core.propagation.PropagationTags.HeaderType.DATADOG; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import datadog.trace.api.Config; @@ -18,39 +24,32 @@ import datadog.trace.core.DDCoreJavaSpecification; import datadog.trace.core.DDSpanContext; import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; -import datadog.trace.test.util.JavaStringUtils; -import java.util.EnumSet; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.converter.ConvertWith; import org.tabletest.junit.TableTest; -public class HttpInjectorTest extends DDCoreJavaSpecification { +class HttpInjectorTest extends DDCoreJavaSpecification { + private CoreTracer tracer; - protected boolean tracePropagationB3Padding() { - return false; - } - - private String idOrPadded(DDTraceId id) { - if (id.toHighOrderLong() == 0) { - return idOrPadded(DDSpanId.toHexString(id.toLong()), 32); - } - return id.toHexString(); + @BeforeEach + void setup() { + ListWriter writer = new ListWriter(); + tracer = tracerBuilder().writer(writer).build(); } - private String idOrPadded(long id) { - return idOrPadded(DDSpanId.toHexString(id), 16); + @AfterEach + void tearDown() { + tracer.close(); } - private String idOrPadded(String id, int size) { - if (!tracePropagationB3Padding()) { - return id.toLowerCase(); - } - return JavaStringUtils.padHexLower(id, size); + protected boolean tracePropagationB3Padding() { + return DEFAULT_PROPAGATION_B3_PADDING_ENABLED; } @TableTest({ @@ -70,62 +69,61 @@ private String idOrPadded(String id, int size) { "B3MULTI only keep saipan | [B3MULTI] | PrioritySampling.SAMPLER_KEEP | 'saipan'", "B3MULTI,DATADOG keep saipan | [B3MULTI, DATADOG] | PrioritySampling.SAMPLER_KEEP | 'saipan'" }) - @SuppressWarnings("unchecked") void injectHttpHeadersUsingStyles( List styles, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String origin) { - Set styleSet = new LinkedHashSet<>(styles); - Config config = mock(Config.class); - when(config.getTracePropagationStylesToInject()).thenReturn(styleSet); - when(config.isTracePropagationStyleB3PaddingEnabled()).thenReturn(tracePropagationB3Padding()); - HttpCodec.Injector injector = - HttpCodec.createInjector( - config, config.getTracePropagationStylesToInject(), new LinkedHashMap<>()); + HttpCodec.Injector injector = createInjector(styles, emptyMap()); + DDTraceId traceId = DDTraceId.ONE; long spanId = 2; - ListWriter writer = new ListWriter(); - CoreTracer tracer = tracerBuilder().writer(writer).build(); - Map baggage = new LinkedHashMap<>(); + Map baggage = new HashMap<>(); baggage.put("k1", "v1"); baggage.put("k2", "v2"); - DDSpanContext mockedContext = - mockedContext(tracer, traceId, spanId, samplingPriority, origin, baggage); - Map carrier = mock(Map.class); - String b3TraceIdHex = idOrPadded(traceId); - String b3SpanIdHex = idOrPadded(spanId); + DDSpanContext mockedContext = mockedContext(traceId, spanId, samplingPriority, origin, baggage); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + Map carrier = new HashMap<>(); + injector.inject(mockedContext, carrier, Map::put); - if (styleSet.contains(TracePropagationStyle.DATADOG)) { - verify(carrier).put(DatadogHttpCodec.TRACE_ID_KEY, traceId.toString()); - verify(carrier).put(DatadogHttpCodec.SPAN_ID_KEY, Long.toString(spanId)); - verify(carrier).put(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k1", "v1"); - verify(carrier).put(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k2", "v2"); + String b3TraceIdHex = traceIdOrPadded(traceId, tracePropagationB3Padding()); + String b3SpanIdHex = spanIdOrPadded(spanId, tracePropagationB3Padding()); + int expectedSize = 0; + if (styles.contains(TracePropagationStyle.DATADOG)) { + assertEquals(traceId.toString(), carrier.get(DatadogHttpCodec.TRACE_ID_KEY)); + assertEquals(Long.toString(spanId), carrier.get(DatadogHttpCodec.SPAN_ID_KEY)); + assertEquals("v1", carrier.get(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k1")); + assertEquals("v2", carrier.get(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k2")); + assertEquals("_dd.p.usr=123", carrier.get(DATADOG_TAGS_KEY)); + expectedSize += 5; if (samplingPriority != UNSET) { - verify(carrier) - .put(DatadogHttpCodec.SAMPLING_PRIORITY_KEY, Integer.toString(samplingPriority)); + assertEquals( + Integer.toString(samplingPriority), + carrier.get(DatadogHttpCodec.SAMPLING_PRIORITY_KEY)); + expectedSize++; } if (origin != null) { - verify(carrier).put(DatadogHttpCodec.ORIGIN_KEY, origin); + assertEquals(origin, carrier.get(DatadogHttpCodec.ORIGIN_KEY)); + expectedSize++; } - verify(carrier).put("x-datadog-tags", "_dd.p.usr=123"); } - if (styleSet.contains(TracePropagationStyle.B3MULTI)) { - verify(carrier).put(B3HttpCodec.TRACE_ID_KEY, b3TraceIdHex); - verify(carrier).put(B3HttpCodec.SPAN_ID_KEY, b3SpanIdHex); + if (styles.contains(TracePropagationStyle.B3MULTI)) { + assertEquals(b3TraceIdHex, carrier.get(B3HttpCodec.TRACE_ID_KEY)); + assertEquals(b3SpanIdHex, carrier.get(B3HttpCodec.SPAN_ID_KEY)); + expectedSize += 2; if (samplingPriority != UNSET) { - verify(carrier).put(SAMPLING_PRIORITY_KEY, "1"); + assertEquals("1", carrier.get(SAMPLING_PRIORITY_KEY)); + expectedSize++; } } - if (styleSet.contains(TracePropagationStyle.B3SINGLE)) { - if (samplingPriority != UNSET) { - verify(carrier).put(B3_KEY, b3TraceIdHex + "-" + b3SpanIdHex + "-1"); - } else { - verify(carrier).put(B3_KEY, b3TraceIdHex + "-" + b3SpanIdHex); - } + if (styles.contains(TracePropagationStyle.B3SINGLE)) { + String expectedB3Value = + samplingPriority != UNSET + ? b3TraceIdHex + "-" + b3SpanIdHex + "-1" + : b3TraceIdHex + "-" + b3SpanIdHex; + assertEquals(expectedB3Value, carrier.get(B3_KEY)); + expectedSize++; } - verifyNoMoreInteractions(carrier); + assertEquals(expectedSize, carrier.size()); } @TableTest({ @@ -140,60 +138,63 @@ void injectHttpHeadersUsingStyles( "B3MULTI keep no origin | B3MULTI | PrioritySampling.SAMPLER_KEEP | ", "B3MULTI keep saipan | B3MULTI | PrioritySampling.SAMPLER_KEEP | 'saipan'" }) - @SuppressWarnings("unchecked") void injectHttpHeadersUsingStyle( TracePropagationStyle style, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String origin) { - Config config = mock(Config.class); - when(config.isTracePropagationStyleB3PaddingEnabled()).thenReturn(tracePropagationB3Padding()); - Map mapping = new LinkedHashMap<>(); + Map mapping = new HashMap<>(); mapping.put("some-baggage-item", "SOME_HEADER"); - HttpCodec.Injector injector = HttpCodec.createInjector(config, EnumSet.of(style), mapping); + HttpCodec.Injector injector = createInjector(singletonList(style), mapping); + DDTraceId traceId = DDTraceId.ONE; long spanId = 2; - ListWriter writer = new ListWriter(); - CoreTracer tracer = tracerBuilder().writer(writer).build(); - Map baggage = new LinkedHashMap<>(); + Map baggage = new HashMap<>(); baggage.put("k1", "v1"); baggage.put("k2", "v2"); baggage.put("some-baggage-item", "some-baggage-value"); - DDSpanContext mockedContext = - mockedContext(tracer, traceId, spanId, samplingPriority, origin, baggage); - Map carrier = mock(Map.class); - String b3TraceIdHex = idOrPadded(traceId); - String b3SpanIdHex = idOrPadded(spanId); + DDSpanContext mockedContext = mockedContext(traceId, spanId, samplingPriority, origin, baggage); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + Map carrier = new HashMap<>(); + injector.inject(mockedContext, carrier, Map::put); + String b3TraceIdHex = traceIdOrPadded(traceId, tracePropagationB3Padding()); + String b3SpanIdHex = spanIdOrPadded(spanId, tracePropagationB3Padding()); + int expectedSize = 0; if (style == TracePropagationStyle.DATADOG) { - verify(carrier).put(DatadogHttpCodec.TRACE_ID_KEY, traceId.toString()); - verify(carrier).put(DatadogHttpCodec.SPAN_ID_KEY, Long.toString(spanId)); - verify(carrier).put(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k1", "v1"); - verify(carrier).put(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k2", "v2"); - verify(carrier).put("SOME_HEADER", "some-baggage-value"); + assertEquals(traceId.toString(), carrier.get(DatadogHttpCodec.TRACE_ID_KEY)); + assertEquals(Long.toString(spanId), carrier.get(DatadogHttpCodec.SPAN_ID_KEY)); + assertEquals("v1", carrier.get(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k1")); + assertEquals("v2", carrier.get(DatadogHttpCodec.OT_BAGGAGE_PREFIX + "k2")); + assertEquals("some-baggage-value", carrier.get("SOME_HEADER")); + assertEquals("_dd.p.usr=123", carrier.get(DATADOG_TAGS_KEY)); + expectedSize = 6; if (samplingPriority != UNSET) { - verify(carrier) - .put(DatadogHttpCodec.SAMPLING_PRIORITY_KEY, Integer.toString(samplingPriority)); + assertEquals( + Integer.toString(samplingPriority), + carrier.get(DatadogHttpCodec.SAMPLING_PRIORITY_KEY)); + expectedSize++; } if (origin != null) { - verify(carrier).put(DatadogHttpCodec.ORIGIN_KEY, origin); + assertEquals(origin, carrier.get(DatadogHttpCodec.ORIGIN_KEY)); + expectedSize++; } - verify(carrier).put("x-datadog-tags", "_dd.p.usr=123"); } else if (style == TracePropagationStyle.B3MULTI) { - verify(carrier).put(B3HttpCodec.TRACE_ID_KEY, b3TraceIdHex); - verify(carrier).put(B3HttpCodec.SPAN_ID_KEY, b3SpanIdHex); + assertEquals(b3TraceIdHex, carrier.get(B3HttpCodec.TRACE_ID_KEY)); + assertEquals(b3SpanIdHex, carrier.get(B3HttpCodec.SPAN_ID_KEY)); + expectedSize = 2; if (samplingPriority != UNSET) { - verify(carrier).put(SAMPLING_PRIORITY_KEY, "1"); + assertEquals("1", carrier.get(SAMPLING_PRIORITY_KEY)); + expectedSize++; } } else if (style == TracePropagationStyle.B3SINGLE) { - if (samplingPriority != UNSET) { - verify(carrier).put(B3_KEY, b3TraceIdHex + "-" + b3SpanIdHex + "-1"); - } else { - verify(carrier).put(B3_KEY, b3TraceIdHex + "-" + b3SpanIdHex); - } + String expectedB3Value = + samplingPriority != UNSET + ? b3TraceIdHex + "-" + b3SpanIdHex + "-1" + : b3TraceIdHex + "-" + b3SpanIdHex; + assertEquals(expectedB3Value, carrier.get(B3_KEY)); + expectedSize++; } - verifyNoMoreInteractions(carrier); + assertEquals(expectedSize, carrier.size()); } @TableTest({ @@ -202,11 +203,8 @@ void injectHttpHeadersUsingStyle( "tracecontext encoding | TRACECONTEXT", "haystack encoding | HAYSTACK " }) - @SuppressWarnings("unchecked") void encodeBaggageInHttpHeadersUsingStyle(TracePropagationStyle style) { - Config config = mock(Config.class); - when(config.isTracePropagationStyleB3PaddingEnabled()).thenReturn(tracePropagationB3Padding()); - Map baggage = new LinkedHashMap<>(); + Map baggage = new HashMap<>(); baggage.put("alpha", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); baggage.put("num", "01234567890"); baggage.put("whitespace", "ab \tcd"); @@ -214,25 +212,35 @@ void encodeBaggageInHttpHeadersUsingStyle(TracePropagationStyle style) { baggage.put("excluded", "ab',:\\cd"); Map mapping = baggage.keySet().stream().collect(Collectors.toMap(key -> key, key -> key)); - HttpCodec.Injector injector = HttpCodec.createInjector(config, EnumSet.of(style), mapping); + HttpCodec.Injector injector = createInjector(singletonList(style), mapping); + DDTraceId traceId = DDTraceId.ONE; long spanId = 2; - ListWriter writer = new ListWriter(); - CoreTracer tracer = tracerBuilder().writer(writer).build(); - DDSpanContext mockedContext = mockedContext(tracer, traceId, spanId, UNSET, null, baggage); - Map carrier = mock(Map.class); + DDSpanContext mockedContext = mockedContext(traceId, spanId, UNSET, null, baggage); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + Map carrier = new HashMap<>(); + injector.inject(mockedContext, carrier, Map::put); - verify(carrier).put("alpha", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); - verify(carrier).put("num", "01234567890"); - verify(carrier).put("whitespace", "ab%20%09cd"); - verify(carrier).put("specials", "ab.-*_cd"); - verify(carrier).put("excluded", "ab%27%2C%3A%5Ccd"); + assertEquals("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", carrier.get("alpha")); + assertEquals("01234567890", carrier.get("num")); + assertEquals("ab%20%09cd", carrier.get("whitespace")); + assertEquals("ab.-*_cd", carrier.get("specials")); + assertEquals("ab%27%2C%3A%5Ccd", carrier.get("excluded")); } - static DDSpanContext mockedContext( - CoreTracer tracer, + HttpCodec.Injector createInjector( + List overriddenStyles, Map invertedBaggageMapping) { + Config config = mock(Config.class); + if (overriddenStyles != null) { + LinkedHashSet orderedSet = new LinkedHashSet<>(overriddenStyles); + when(config.getTracePropagationStylesToInject()).thenReturn(orderedSet); + } + when(config.isTracePropagationStyleB3PaddingEnabled()).thenReturn(tracePropagationB3Padding()); + return HttpCodec.createInjector( + config, config.getTracePropagationStylesToInject(), invertedBaggageMapping); + } + + DDSpanContext mockedContext( DDTraceId traceId, long spanId, int samplingPriority, @@ -252,12 +260,18 @@ static DDSpanContext mockedContext( false, "fakeType", 0, - tracer.createTraceCollector(DDTraceId.ONE), + this.tracer.createTraceCollector(DDTraceId.ONE), null, null, NoopPathwayContext.INSTANCE, false, - PropagationTags.factory() - .fromHeaderValue(PropagationTags.HeaderType.DATADOG, "_dd.p.usr=123")); + PropagationTags.factory().fromHeaderValue(DATADOG, "_dd.p.usr=123")); + } + + static class HttpInjectorNonPaddedTest extends HttpInjectorTest { + @Override + protected boolean tracePropagationB3Padding() { + return false; + } } } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/MapSetter.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/MapSetter.java deleted file mode 100644 index fda7aa39ccf..00000000000 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/MapSetter.java +++ /dev/null @@ -1,15 +0,0 @@ -package datadog.trace.core.propagation; - -import datadog.context.propagation.CarrierSetter; -import java.util.Map; -import javax.annotation.ParametersAreNonnullByDefault; - -@ParametersAreNonnullByDefault -public class MapSetter implements CarrierSetter> { - public static final MapSetter INSTANCE = new MapSetter(); - - @Override - public void set(Map carrier, String key, String value) { - carrier.put(key, value); - } -} diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/NoneHttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/NoneHttpExtractorTest.java index 6481c2ff456..81d885b0b2f 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/NoneHttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/NoneHttpExtractorTest.java @@ -1,14 +1,16 @@ package datadog.trace.core.propagation; +import static datadog.trace.api.config.TracerConfig.PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED; +import static datadog.trace.api.config.TracerConfig.REQUEST_HEADER_TAGS_COMMA_ALLOWED; import static datadog.trace.api.sampling.PrioritySampling.UNSET; +import static datadog.trace.bootstrap.ActiveSubsystems.APPSEC_ACTIVE; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; import static datadog.trace.core.propagation.DatadogHttpCodec.DATADOG_TAGS_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.ORIGIN_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX; -import static datadog.trace.core.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.SPAN_ID_KEY; import static datadog.trace.core.propagation.DatadogHttpCodec.TRACE_ID_KEY; -import static datadog.trace.junit.utils.config.WithConfigExtension.injectEnvConfig; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -24,12 +26,11 @@ import datadog.trace.api.DynamicConfig; import datadog.trace.api.config.TracerConfig; import datadog.trace.api.internal.util.LongStringUtils; -import datadog.trace.bootstrap.ActiveSubsystems; import datadog.trace.bootstrap.instrumentation.api.TagContext; import datadog.trace.junit.utils.config.WithConfig; -import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import datadog.trace.test.util.DDJavaSpecification; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -39,9 +40,8 @@ import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; -@WithConfig(key = "propagation.extract.log_header_names.enabled", value = "true") +@WithConfig(key = PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED, value = "true") class NoneHttpExtractorTest extends DDJavaSpecification { - private static final String SOME_HEADER = "SOME_HEADER"; private static final String SOME_CUSTOM_BAGGAGE_HEADER = "SOME_CUSTOM_BAGGAGE_HEADER"; private static final String SOME_CUSTOM_BAGGAGE_HEADER_2 = "SOME_CUSTOM_BAGGAGE_HEADER_2"; @@ -49,98 +49,116 @@ class NoneHttpExtractorTest extends DDJavaSpecification { private static final String SOME_BAGGAGE = "some-baggage"; private static final String SOME_CASE_SENSITIVE_BAGGAGE = "some-CaseSensitive-baggage"; - private DynamicConfig dynamicConfig; - private HttpCodec.Extractor lazyExtractor; + private HttpCodec.Extractor extractor; private boolean origAppSecActive; @BeforeEach void setup() { - Map baggageMap = new LinkedHashMap<>(); + Map baggageMap = new HashMap<>(); baggageMap.put(SOME_CUSTOM_BAGGAGE_HEADER, SOME_BAGGAGE); baggageMap.put(SOME_CUSTOM_BAGGAGE_HEADER_2, SOME_CASE_SENSITIVE_BAGGAGE); - dynamicConfig = + DynamicConfig dynamicConfig = DynamicConfig.create() .setHeaderTags(singletonMap(SOME_HEADER, SOME_TAG)) .setBaggageMapping(baggageMap) .apply(); - origAppSecActive = ActiveSubsystems.APPSEC_ACTIVE; - ActiveSubsystems.APPSEC_ACTIVE = true; + this.extractor = NoneCodec.newExtractor(Config.get(), dynamicConfig::captureTraceConfig); + + this.origAppSecActive = APPSEC_ACTIVE; + APPSEC_ACTIVE = true; } @AfterEach void teardown() { - ActiveSubsystems.APPSEC_ACTIVE = origAppSecActive; - extractor().cleanup(); - } - - private HttpCodec.Extractor extractor() { - if (lazyExtractor == null) { - lazyExtractor = createExtractor(); - } - return lazyExtractor; - } - - private HttpCodec.Extractor createExtractor() { - return NoneCodec.newExtractor(Config.get(), () -> dynamicConfig.captureTraceConfig()); + APPSEC_ACTIVE = origAppSecActive; + this.extractor.cleanup(); } @TableTest({ - "scenario | traceId | spanId | samplingPriority | origin | allowComma", - "no origin comma | '1' | '2' | PrioritySampling.UNSET | | true ", - "no origin no comma | '2' | '3' | PrioritySampling.UNSET | | false ", - "uint64 max comma | '18446744073709551615' | '18446744073709551614' | PrioritySampling.UNSET | | true ", - "uint64 max-1 | '18446744073709551614' | '18446744073709551615' | PrioritySampling.UNSET | | false " + "scenario | traceId | spanId ", + "no origin | '1' | '2' ", + "uint64 max | 'TRACE_ID_MAX' | 'TRACE_ID_MAX-1'", + "uint64 max-1 | 'TRACE_ID_MAX-1' | 'TRACE_ID_MAX' " }) void extractHttpHeaders( - String traceId, - String spanId, - @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, - String origin, - boolean allowComma) { - injectEnvConfig( - "DD_TRACE_REQUEST_HEADER_TAGS_COMMA_ALLOWED", String.valueOf(allowComma), false); - HttpCodec.Extractor extractor = createExtractor(); - Map headers = new LinkedHashMap<>(); - headers.put("", "empty key"); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId); - headers.put(SPAN_ID_KEY.toUpperCase(), spanId); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info,and-more"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); - if (samplingPriority != UNSET) { - headers.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority)); - } - if (origin != null) { - headers.put(ORIGIN_KEY, origin); - } - String expectedTagValue = allowComma ? "my-interesting-info,and-more" : "my-interesting-info"; - - TagContext context = extractor.extract(headers, stringValuesMap()); + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId) { + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, traceId, + SPAN_ID_KEY, spanId, + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info,and-more", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on + + TagContext context = this.extractor.extract(headers, stringValuesMap()); assertEquals(DDTraceId.ZERO, context.getTraceId()); assertEquals(DDSpanId.ZERO, context.getSpanId()); - Map expectedBaggage = new LinkedHashMap<>(); + Map expectedBaggage = new HashMap<>(); expectedBaggage.put(SOME_BAGGAGE, "my-interesting-baggage-info"); expectedBaggage.put(SOME_CASE_SENSITIVE_BAGGAGE, "my-interesting-baggage-info-2"); assertEquals(expectedBaggage, context.getBaggage()); - assertEquals(singletonMap(SOME_TAG, expectedTagValue), context.getTags()); - assertEquals(samplingPriority, context.getSamplingPriority()); - assertEquals(origin, asString(context.getOrigin())); - extractor.cleanup(); + assertEquals(singletonMap(SOME_TAG, "my-interesting-info,and-more"), context.getTags()); + assertEquals(UNSET, context.getSamplingPriority()); + assertNull(context.getOrigin()); + } + + @WithConfig(key = REQUEST_HEADER_TAGS_COMMA_ALLOWED, value = "false") + @Test + void extractHttpHeadersWithoutComma() { + // Recreate extractor with the comma-disallowed config + this.extractor.cleanup(); + Map baggageMap = new HashMap<>(); + baggageMap.put(SOME_CUSTOM_BAGGAGE_HEADER, SOME_BAGGAGE); + baggageMap.put(SOME_CUSTOM_BAGGAGE_HEADER_2, SOME_CASE_SENSITIVE_BAGGAGE); + DynamicConfig dynamicConfig = + DynamicConfig.create() + .setHeaderTags(singletonMap(SOME_HEADER, SOME_TAG)) + .setBaggageMapping(baggageMap) + .apply(); + this.extractor = NoneCodec.newExtractor(Config.get(), dynamicConfig::captureTraceConfig); + + // spotless:off + Map headers = headers( + "", "empty key", + TRACE_ID_KEY, "2", + SPAN_ID_KEY, "3", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info,and-more", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on + + TagContext context = this.extractor.extract(headers, stringValuesMap()); + + assertEquals(DDTraceId.ZERO, context.getTraceId()); + assertEquals(DDSpanId.ZERO, context.getSpanId()); + Map expectedBaggage = new HashMap<>(); + expectedBaggage.put(SOME_BAGGAGE, "my-interesting-baggage-info"); + expectedBaggage.put(SOME_CASE_SENSITIVE_BAGGAGE, "my-interesting-baggage-info-2"); + assertEquals(expectedBaggage, context.getBaggage()); + assertEquals(singletonMap(SOME_TAG, "my-interesting-info"), context.getTags()); } @ParameterizedTest @ValueSource(booleans = {false, true}) void extractHeaderTagsWithNoPropagation(boolean withOrigin) { - Map headers = new LinkedHashMap<>(); - if (withOrigin) { - headers.put(ORIGIN_KEY, "my-origin"); - } - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + ORIGIN_KEY, withOrigin ? "my-origin" : null, + SOME_HEADER, "my-interesting-info" + ); + // spotless:on - TagContext context = extractor().extract(headers, stringValuesMap()); + TagContext context = this.extractor.extract(headers, stringValuesMap()); assertFalse(context instanceof ExtractedContext); assertEquals(singletonMap(SOME_TAG, "my-interesting-info"), context.getTags()); @@ -152,19 +170,22 @@ void extractHeadersWithForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; String forwarded = "for=" + forwardedIp + ":" + forwardedPort; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "Forwarded", forwarded + ); + // spotless:on - TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); + TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); assertNotNull(context); assertFalse(context instanceof ExtractedContext); assertEquals(forwarded, context.getForwarded()); - context = extractor().extract(fullCtx, stringValuesMap()); + context = this.extractor.extract(fullCtx, stringValuesMap()); assertFalse(context instanceof ExtractedContext); assertEquals(DDTraceId.ZERO, context.getTraceId()); @@ -176,23 +197,27 @@ void extractHeadersWithForwarding() { void extractHeadersWithXForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; - Map tagOnlyCtx = new LinkedHashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", forwardedIp); - tagOnlyCtx.put("X-Forwarded-Port", forwardedPort); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put(TRACE_ID_KEY.toUpperCase(), "1"); - fullCtx.put(SPAN_ID_KEY.toUpperCase(), "2"); - fullCtx.put("x-forwarded-for", forwardedIp); - fullCtx.put("x-forwarded-port", forwardedPort); - - TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", forwardedIp, + "X-Forwarded-Port", forwardedPort + ); + Map fullCtx = headers( + TRACE_ID_KEY, "1", + SPAN_ID_KEY, "2", + "x-forwarded-for", forwardedIp, + "x-forwarded-port", forwardedPort + ); + // spotless:on + + TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); assertNotNull(context); assertFalse(context instanceof ExtractedContext); assertEquals(forwardedIp, context.getXForwardedFor()); assertEquals(forwardedPort, context.getXForwardedPort()); - context = extractor().extract(fullCtx, stringValuesMap()); + context = this.extractor.extract(fullCtx, stringValuesMap()); assertFalse(context instanceof ExtractedContext); assertEquals(DDTraceId.ZERO, context.getTraceId()); @@ -204,17 +229,17 @@ void extractHeadersWithXForwarding() { @Test void extractEmptyHeadersReturnsNull() { assertNull( - extractor().extract(singletonMap("ignored-header", "ignored-value"), stringValuesMap())); + this.extractor.extract(headers("ignored-header", "ignored-value"), stringValuesMap())); } @Test @WithConfig(key = TracerConfig.TRACE_CLIENT_IP_RESOLVER_ENABLED, value = "false") void extractHeadersWithIpResolutionDisabled() { - Map tagOnlyCtx = new LinkedHashMap<>(); + Map tagOnlyCtx = new HashMap<>(); tagOnlyCtx.put("X-Forwarded-For", "::1"); tagOnlyCtx.put("User-agent", "foo/bar"); - TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); + TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); assertNotNull(context); assertNull(context.getXForwardedFor()); @@ -223,12 +248,12 @@ void extractHeadersWithIpResolutionDisabled() { @Test void extractHeadersWithIpResolutionDisabledAppsecDisabled() { - ActiveSubsystems.APPSEC_ACTIVE = false; - Map tagOnlyCtx = new LinkedHashMap<>(); + APPSEC_ACTIVE = false; + Map tagOnlyCtx = new HashMap<>(); tagOnlyCtx.put("X-Forwarded-For", "::1"); tagOnlyCtx.put("User-agent", "foo/bar"); - TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); + TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); assertNotNull(context); assertNull(context.getXForwardedFor()); @@ -237,11 +262,11 @@ void extractHeadersWithIpResolutionDisabledAppsecDisabled() { @Test @WithConfig(key = TracerConfig.TRACE_CLIENT_IP_HEADER, value = "my-header") void customIpHeaderCollectionDoesNotDisableStandardIpHeaderCollection() { - Map tagOnlyCtx = new LinkedHashMap<>(); + Map tagOnlyCtx = new HashMap<>(); tagOnlyCtx.put("X-Forwarded-For", "::1"); tagOnlyCtx.put("My-Header", "8.8.8.8"); - TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); + TagContext context = this.extractor.extract(tagOnlyCtx, stringValuesMap()); assertNotNull(context); assertEquals("::1", context.getXForwardedFor()); @@ -259,19 +284,20 @@ void customIpHeaderCollectionDoesNotDisableStandardIpHeaderCollection() { void extractHttpHeadersWith128BitTraceId(String hexId) { DD128bTraceId traceId = DD128bTraceId.fromHex(hexId); boolean is128bTrace = traceId.toHighOrderLong() != 0; - Map headers = new LinkedHashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), traceId.toString()); - headers.put(SPAN_ID_KEY.toUpperCase(), "2"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - if (is128bTrace) { - headers.put( - DATADOG_TAGS_KEY.toUpperCase(), - "_dd.p.tid=" + LongStringUtils.toHexStringPadded(traceId.toHighOrderLong(), 16)); - } - - TagContext context = extractor().extract(headers, stringValuesMap()); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, traceId.toString(), + SPAN_ID_KEY, "2", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info", + DATADOG_TAGS_KEY, is128bTrace + ? "_dd.p.tid=" + LongStringUtils.toHexStringPadded(traceId.toHighOrderLong(), 16) + : null + ); + // spotless:on + + TagContext context = this.extractor.extract(headers, stringValuesMap()); assertEquals(DDTraceId.ZERO, context.getTraceId()); assertEquals(DDSpanId.ZERO, context.getSpanId()); @@ -281,14 +307,17 @@ void extractHttpHeadersWith128BitTraceId(String hexId) { @Test void extractHttpHeadersWithInvalidNonNumericId() { - Map headers = new LinkedHashMap<>(); - headers.put(TRACE_ID_KEY.toUpperCase(), "traceId"); - headers.put(SPAN_ID_KEY.toUpperCase(), "spanId"); - headers.put((OT_BAGGAGE_PREFIX + "k1").toUpperCase(), "v1"); - headers.put((OT_BAGGAGE_PREFIX + "k2").toUpperCase(), "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - - TagContext context = extractor().extract(headers, stringValuesMap()); + // spotless:off + Map headers = headers( + TRACE_ID_KEY, "traceId", + SPAN_ID_KEY,"spanId", + OT_BAGGAGE_PREFIX + "k1", "v1", + OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on + + TagContext context = this.extractor.extract(headers, stringValuesMap()); assertInstanceOf(TagContext.class, context); assertEquals(singletonMap(SOME_TAG, "my-interesting-info"), context.getTags()); @@ -296,19 +325,21 @@ void extractHttpHeadersWithInvalidNonNumericId() { @Test void extractCommonHttpHeaders() { - Map headers = new LinkedHashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); - - TagContext context = extractor().extract(headers, stringValuesMap()); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:on + + TagContext context = this.extractor.extract(headers, stringValuesMap()); assertEquals("some-user-agent", context.getUserAgent()); assertEquals("1.1.1.1", context.getXClusterClientIp()); @@ -321,8 +352,4 @@ void extractCommonHttpHeaders() { assertEquals("8.8.8.8", context.getCfConnectingIp()); assertEquals("9.9.9.9", context.getCfConnectingIpv6()); } - - private static String asString(CharSequence cs) { - return cs == null ? null : cs.toString(); - } } diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpExtractorTest.java index f72e1068b5e..8ee8c4ecf33 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpExtractorTest.java @@ -1,6 +1,7 @@ package datadog.trace.core.propagation; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -110,10 +111,7 @@ void extractTraceparent( String traceIdHex, long spanId, @ConvertWith(PrioritySamplingConverter.class) byte priority) { - Map headers = new LinkedHashMap<>(); - if (traceparent != null) { - headers.put(W3CHttpCodec.TRACE_PARENT_KEY, traceparent); - } + Map headers = headers(W3CHttpCodec.TRACE_PARENT_KEY, traceparent); TagContext result = extractor().extract(headers, stringValuesMap()); @@ -154,15 +152,18 @@ void extractTraceparentTracestateAndHttpHeaders( @ConvertWith(PrioritySamplingConverter.class) byte priority, @ConvertWith(SamplingMechanismConverter.class) Byte decisionMaker, String origin) { - Map headers = new LinkedHashMap<>(); - headers.put("", "empty key"); - headers.put(W3CHttpCodec.TRACE_PARENT_KEY.toUpperCase(), traceparent); - headers.put(W3CHttpCodec.TRACE_STATE_KEY.toUpperCase(), tracestate); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k1", "v1"); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k2", "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); + // spotless:off + Map headers = headers( + "", "empty key", + W3CHttpCodec.TRACE_PARENT_KEY, traceparent, + W3CHttpCodec.TRACE_STATE_KEY, tracestate, + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k1", "v1", + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on ExtractedContext context = (ExtractedContext) extractor().extract(headers, stringValuesMap()); @@ -190,7 +191,7 @@ void extractTraceparentTracestateAndHttpHeaders( @Test void extractHeaderTagsWithNoPropagation() { - Map headers = singletonMap(SOME_HEADER, "my-interesting-info"); + Map headers = headers(SOME_HEADER, "my-interesting-info"); TagContext context = extractor().extract(headers, stringValuesMap()); @@ -203,12 +204,13 @@ void extractHeadersWithForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; String forwarded = "for=" + forwardedIp + ":" + forwardedPort; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put( - W3CHttpCodec.TRACE_PARENT_KEY.toUpperCase(), - "00-00000000000000000000000000000001-0000000000000002-01"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + W3CHttpCodec.TRACE_PARENT_KEY, "00-00000000000000000000000000000001-0000000000000002-01", + "Forwarded", forwarded + ); + // spotless:on TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); @@ -228,15 +230,17 @@ void extractHeadersWithForwarding() { void extractHeadersWithXForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; - Map tagOnlyCtx = new LinkedHashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", forwardedIp); - tagOnlyCtx.put("X-Forwarded-Port", forwardedPort); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put( - W3CHttpCodec.TRACE_PARENT_KEY.toUpperCase(), - "00-00000000000000000000000000000001-0000000000000002-01"); - fullCtx.put("x-forwarded-for", forwardedIp); - fullCtx.put("x-forwarded-port", forwardedPort); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", forwardedIp, + "X-Forwarded-Port", forwardedPort + ); + Map fullCtx = headers( + W3CHttpCodec.TRACE_PARENT_KEY, "00-00000000000000000000000000000001-0000000000000002-01", + "x-forwarded-for", forwardedIp, + "x-forwarded-port", forwardedPort + ); + // spotless:on TagContext context = extractor().extract(tagOnlyCtx, stringValuesMap()); @@ -256,8 +260,7 @@ void extractHeadersWithXForwarding() { @Test void extractEmptyHeadersReturnsNull() { - assertNull( - extractor().extract(singletonMap("ignored-header", "ignored-value"), stringValuesMap())); + assertNull(extractor().extract(headers("ignored-header", "ignored-value"), stringValuesMap())); } @Test @@ -307,18 +310,18 @@ void customIpHeaderCollectionDoesNotDisableStandardIpHeaderCollection() { "non-zero start time | 1610001234 " }) void extractHttpHeadersWithEndToEnd(long endToEndStartTime) { - Map headers = new LinkedHashMap<>(); - headers.put("", "empty key"); - headers.put( - W3CHttpCodec.TRACE_PARENT_KEY.toUpperCase(), - "00-00000000000000000000000000000001-123456789abcdef0-01"); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k1", "v1"); - headers.put( - W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "t0", String.valueOf(endToEndStartTime)); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k2", "v2"); - headers.put(SOME_HEADER, "my-interesting-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); + // spotless:off + Map headers = headers( + "", "empty key", + W3CHttpCodec.TRACE_PARENT_KEY, "00-00000000000000000000000000000001-123456789abcdef0-01", + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k1", "v1", + W3CHttpCodec.OT_BAGGAGE_PREFIX + "t0", String.valueOf(endToEndStartTime), + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_HEADER, "my-interesting-info", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2" + ); + // spotless:on ExtractedContext context = (ExtractedContext) extractor().extract(headers, stringValuesMap()); @@ -341,12 +344,15 @@ void extractHttpHeadersWithEndToEnd(long endToEndStartTime) { "valid traceparent | true | '00-00000000000000000000000000000001-0000000000000001-01'" }) void baggageIsMappedOnContextCreation(boolean tpValid, String traceparent) { - Map headers = new LinkedHashMap<>(); - headers.put(W3CHttpCodec.TRACE_PARENT_KEY, traceparent); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue"); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k1", "v1"); - headers.put(W3CHttpCodec.OT_BAGGAGE_PREFIX.toUpperCase() + "k2", "v2"); - headers.put(SOME_ARBITRARY_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + W3CHttpCodec.TRACE_PARENT_KEY, traceparent, + SOME_CUSTOM_BAGGAGE_HEADER, "mappedBaggageValue", + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k1", "v1", + W3CHttpCodec.OT_BAGGAGE_PREFIX + "k2", "v2", + SOME_ARBITRARY_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = extractor().extract(headers, stringValuesMap()); @@ -364,17 +370,20 @@ void baggageIsMappedOnContextCreation(boolean tpValid, String traceparent) { @Test void extractCommonHttpHeaders() { - Map headers = new LinkedHashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9" + ); + // spotless:on TagContext context = extractor().extract(headers, stringValuesMap()); @@ -398,9 +407,11 @@ void extractCommonHttpHeaders() { }) void markInconsistentTidAsPropagationError( String traceparent, String tracestate, boolean consistent) { - Map headers = new LinkedHashMap<>(); - headers.put(W3CHttpCodec.TRACE_PARENT_KEY.toUpperCase(), traceparent); - headers.put(W3CHttpCodec.TRACE_STATE_KEY.toUpperCase(), tracestate); + // spotless:off + Map headers = headers( + W3CHttpCodec.TRACE_PARENT_KEY, traceparent, + W3CHttpCodec.TRACE_STATE_KEY, tracestate); + // spotless:on ExtractedContext context = (ExtractedContext) extractor().extract(headers, stringValuesMap()); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpInjectorTest.java index 0ffdf1e6e6c..c580db9aa17 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/W3CHttpInjectorTest.java @@ -18,6 +18,7 @@ import datadog.trace.core.DDCoreJavaSpecification; import datadog.trace.core.DDSpanContext; import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -37,16 +38,16 @@ void setup() { } @TableTest({ - "scenario | traceId | spanId | samplingPriority | origin | tracestate ", - "unset 1->2 | 1 | 2 | PrioritySampling.UNSET | | 'dd=p:0000000000000002;t.usr:123' ", - "keep 1->4 saipan | 1 | 4 | PrioritySampling.SAMPLER_KEEP | saipan | 'dd=s:1;o:saipan;p:0000000000000004;t.usr:123'", - "unset max->max-1 saipan | 18446744073709551615 | 18446744073709551614 | PrioritySampling.UNSET | saipan | 'dd=o:saipan;p:fffffffffffffffe;t.usr:123' ", - "keep max-1->max | 18446744073709551614 | 18446744073709551615 | PrioritySampling.SAMPLER_KEEP | | 'dd=s:1;p:ffffffffffffffff;t.usr:123' ", - "drop max-1->max | 18446744073709551614 | 18446744073709551615 | PrioritySampling.SAMPLER_DROP | | 'dd=s:0;p:ffffffffffffffff;t.usr:123' " + "scenario | traceId | spanId | samplingPriority | origin | tracestate ", + "unset 1->2 | 1 | 2 | PrioritySampling.UNSET | | 'dd=p:0000000000000002;t.usr:123' ", + "keep 1->4 saipan | 1 | 4 | PrioritySampling.SAMPLER_KEEP | saipan | 'dd=s:1;o:saipan;p:0000000000000004;t.usr:123'", + "unset max->max-1 saipan | TRACE_ID_MAX | TRACE_ID_MAX-1 | PrioritySampling.UNSET | saipan | 'dd=o:saipan;p:fffffffffffffffe;t.usr:123' ", + "keep max-1->max | TRACE_ID_MAX-1 | TRACE_ID_MAX | PrioritySampling.SAMPLER_KEEP | | 'dd=s:1;p:ffffffffffffffff;t.usr:123' ", + "drop max-1->max | TRACE_ID_MAX-1 | TRACE_ID_MAX | PrioritySampling.SAMPLER_DROP | | 'dd=s:0;p:ffffffffffffffff;t.usr:123' " }) void injectHttpHeaders( - String traceId, - String spanId, + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String origin, String tracestate) { @@ -74,7 +75,7 @@ void injectHttpHeaders( expected.put(OT_BAGGAGE_PREFIX + "k2", "v2"); expected.put("SOME_CUSTOM_HEADER", "some-value"); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); assertEquals(expected, carrier); @@ -102,7 +103,7 @@ void injectHttpHeadersWithEndToEnd() { mockedContext.beginEndToEnd(); Map carrier = new LinkedHashMap<>(); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); Map expected = new LinkedHashMap<>(); expected.put(TRACE_PARENT_KEY, buildTraceParent("1", "2", PrioritySampling.UNSET)); @@ -135,7 +136,7 @@ void injectTheDecisionMakerTag() { mockedContext.setSamplingPriority(PrioritySampling.USER_KEEP, MANUAL); Map carrier = new LinkedHashMap<>(); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); Map expected = new LinkedHashMap<>(); expected.put(TRACE_PARENT_KEY, buildTraceParent("1", "2", PrioritySampling.USER_KEEP)); @@ -158,7 +159,7 @@ void updateLastParentIdOnChildSpan() { long rootSpanId = rootSpan.getSpanId(); AgentScope rootScope = tracer.activateSpan(rootSpan); - injector.inject((DDSpanContext) rootSpan.context(), carrier, MapSetter.INSTANCE); + injector.inject((DDSpanContext) rootSpan.context(), carrier, Map::put); long lastParentId = extractLastParentId(carrier); // trace state has root span id as last parent @@ -168,7 +169,7 @@ void updateLastParentIdOnChildSpan() { AgentSpan childSpan = tracer.startSpan("test", "child"); long childSpanId = childSpan.getSpanId(); carrier.clear(); - injector.inject((DDSpanContext) childSpan.context(), carrier, MapSetter.INSTANCE); + injector.inject((DDSpanContext) childSpan.context(), carrier, Map::put); lastParentId = extractLastParentId(carrier); // trace state has child span id as last parent @@ -177,7 +178,7 @@ void updateLastParentIdOnChildSpan() { // injecting root span again childSpan.finish(); carrier.clear(); - injector.inject((DDSpanContext) rootSpan.context(), carrier, MapSetter.INSTANCE); + injector.inject((DDSpanContext) rootSpan.context(), carrier, Map::put); lastParentId = extractLastParentId(carrier); // trace state has root span is as last parent again diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpExtractorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpExtractorTest.java index 06c63192cab..ca9dac478ff 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpExtractorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpExtractorTest.java @@ -1,6 +1,7 @@ package datadog.trace.core.propagation; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -70,18 +71,19 @@ void extractHttpHeaders( String spanId, String samplingPriority, @ConvertWith(PrioritySamplingConverter.class) byte expectedSamplingPriority) { - Map headers = new LinkedHashMap<>(); - headers.put( - "X-Amzn-Trace-Id", - "Root=1-00000000-00000000" + // spotless:off + Map headers = headers( + "X-Amzn-Trace-Id", "Root=1-00000000-00000000" + padLeft(traceId, 16, '0') + ";Parent=" + padLeft(spanId, 16, '0') + samplingPriority - + ";=empty key;empty value=;=;;"); - headers.put(SOME_HEADER, "my-interesting-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info"); - headers.put(SOME_CUSTOM_BAGGAGE_HEADER_2, "my-interesting-baggage-info-2"); + + ";=empty key;empty value=;=;;", + SOME_HEADER, "my-interesting-info", + SOME_CUSTOM_BAGGAGE_HEADER, "my-interesting-baggage-info", + SOME_CUSTOM_BAGGAGE_HEADER_2,"my-interesting-baggage-info-2" + ); + // spotless:on ExtractedContext context = (ExtractedContext) extractor.extract(headers, stringValuesMap()); @@ -99,7 +101,7 @@ void extractHttpHeaders( @Test void extractHeaderTagsWithNoPropagation() { - Map headers = singletonMap(SOME_HEADER, "my-interesting-info"); + Map headers = headers(SOME_HEADER, "my-interesting-info"); TagContext context = extractor.extract(headers, stringValuesMap()); @@ -112,11 +114,13 @@ void extractHeadersWithForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; String forwarded = "for=" + forwardedIp + ":" + forwardedPort; - Map tagOnlyCtx = singletonMap("Forwarded", forwarded); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put( - "x-amzn-trace-id", "Root=1-00000000-000000000000000000000001;Parent=0000000000000002"); - fullCtx.put("Forwarded", forwarded); + Map tagOnlyCtx = headers("Forwarded", forwarded); + // spotless:off + Map fullCtx = headers( + "x-amzn-trace-id", "Root=1-00000000-000000000000000000000001;Parent=0000000000000002", + "Forwarded", forwarded + ); + // spotless:on TagContext context = extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -136,14 +140,17 @@ void extractHeadersWithForwarding() { void extractHeadersWithXForwarding() { String forwardedIp = "1.2.3.4"; String forwardedPort = "1234"; - Map tagOnlyCtx = new LinkedHashMap<>(); - tagOnlyCtx.put("X-Forwarded-For", forwardedIp); - tagOnlyCtx.put("X-Forwarded-Port", forwardedPort); - Map fullCtx = new LinkedHashMap<>(); - fullCtx.put( - "x-amzn-trace-id", "Root=1-00000000-000000000000000000000001;Parent=0000000000000002"); - fullCtx.put("x-forwarded-for", forwardedIp); - fullCtx.put("x-forwarded-port", forwardedPort); + // spotless:off + Map tagOnlyCtx = headers( + "X-Forwarded-For", forwardedIp, + "X-Forwarded-Port", forwardedPort + ); + Map fullCtx = headers( + "x-amzn-trace-id", "Root=1-00000000-000000000000000000000001;Parent=0000000000000002", + "x-forwarded-for", forwardedIp, + "x-forwarded-port", forwardedPort + ); + // spotless:on TagContext context = extractor.extract(tagOnlyCtx, stringValuesMap()); @@ -163,16 +170,17 @@ void extractHeadersWithXForwarding() { @Test void noContextWithEmptyHeaders() { - assertNull( - extractor.extract(singletonMap("ignored-header", "ignored-value"), stringValuesMap())); + assertNull(extractor.extract(headers("ignored-header", "ignored-value"), stringValuesMap())); } @Test void noContextWithInvalidNonNumericId() { - Map headers = new LinkedHashMap<>(); - headers.put( - "x-amzn-trace-Id", "Root=1-00000000-00000000000000000traceId;Parent=0000000000spanId"); - headers.put(SOME_HEADER, "my-interesting-info"); + // spotless:off + Map headers = headers( + "x-amzn-trace-Id", "Root=1-00000000-00000000000000000traceId;Parent=0000000000spanId", + SOME_HEADER, "my-interesting-info" + ); + // spotless:on TagContext context = extractor.extract(headers, stringValuesMap()); @@ -182,7 +190,7 @@ void noContextWithInvalidNonNumericId() { @Test void noContextWithTooLargeTraceId() { Map headers = - singletonMap( + headers( "X-Amzn-Trace-Id", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8"); TagContext context = extractor.extract(headers, stringValuesMap()); @@ -193,7 +201,7 @@ void noContextWithTooLargeTraceId() { @Test void extractHttpHeadersWithNonZeroEpoch() { Map headers = - singletonMap( + headers( "X-Amzn-Trace-Id", "Root=1-5759e988-00000000e1be46a994272793;Parent=53995c3f42cd8ad8"); TagContext context = extractor.extract(headers, stringValuesMap()); @@ -214,7 +222,7 @@ void extractHttpHeadersWithNonZeroEpoch() { void extractIdsWhileRetainingTheOriginalString( String traceId, String spanId, String expectedTraceIdHex, long expectedSpanId) { Map headers = - singletonMap( + headers( "X-Amzn-Trace-Id", "Root=1-00000000-00000000" + padLeft(traceId, 16, '0') @@ -236,7 +244,7 @@ void extractIdsWhileRetainingTheOriginalString( }) void extractHeadersWithEndToEnd(String traceId, String spanId, long endToEndStartTime) { Map headers = - singletonMap( + headers( "X-Amzn-Trace-Id", "Root=1-00000000-00000000" + padLeft(traceId, 16, '0') @@ -259,17 +267,20 @@ void extractHeadersWithEndToEnd(String traceId, String spanId, long endToEndStar @Test void extractCommonHttpHeaders() { - Map headers = new LinkedHashMap<>(); - headers.put(HttpCodec.USER_AGENT_KEY, "some-user-agent"); - headers.put(HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1"); - headers.put(HttpCodec.X_REAL_IP_KEY, "2.2.2.2"); - headers.put(HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3"); - headers.put(HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4"); - headers.put(HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5"); - headers.put(HttpCodec.FORWARDED_KEY, "6.6.6.6"); - headers.put(HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7"); - headers.put(HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8"); - headers.put(HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9"); + // spotless:off + Map headers = headers( + HttpCodec.USER_AGENT_KEY, "some-user-agent", + HttpCodec.X_CLUSTER_CLIENT_IP_KEY, "1.1.1.1", + HttpCodec.X_REAL_IP_KEY, "2.2.2.2", + HttpCodec.X_CLIENT_IP_KEY, "3.3.3.3", + HttpCodec.TRUE_CLIENT_IP_KEY, "4.4.4.4", + HttpCodec.FORWARDED_FOR_KEY, "5.5.5.5", + HttpCodec.FORWARDED_KEY, "6.6.6.6", + HttpCodec.FASTLY_CLIENT_IP_KEY, "7.7.7.7", + HttpCodec.CF_CONNECTING_IP_KEY, "8.8.8.8", + HttpCodec.CF_CONNECTING_IP_V6_KEY, "9.9.9.9" + ); + // spotless:on TagContext context = extractor.extract(headers, stringValuesMap()); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpInjectorTest.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpInjectorTest.java index dc7a123f262..886d686c9e3 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpInjectorTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/XRayHttpInjectorTest.java @@ -1,6 +1,7 @@ package datadog.trace.core.propagation; import static datadog.trace.bootstrap.instrumentation.api.ContextVisitors.stringValuesMap; +import static datadog.trace.core.propagation.HttpCodecTestHelper.headers; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.mockito.Mockito.clearInvocations; @@ -24,6 +25,7 @@ import datadog.trace.core.DDSpanContext; import datadog.trace.core.datastreams.DataStreamsMonitoring; import datadog.trace.junit.utils.tabletest.PrioritySamplingConverter; +import datadog.trace.junit.utils.tabletest.TraceIdConverter; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -41,19 +43,19 @@ void setup() { } @TableTest({ - "scenario | traceId | spanId | samplingPriority | expectedTraceHeader ", - "unset 1->2 | 1 | 2 | PrioritySampling.UNSET | 'Root=1-633c7675-000000000000000000000001;Parent=0000000000000002;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v' ", - "keep 2->3 | 2 | 3 | PrioritySampling.SAMPLER_KEEP | 'Root=1-633c7675-000000000000000000000002;Parent=0000000000000003;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", - "drop 4->5 | 4 | 5 | PrioritySampling.SAMPLER_DROP | 'Root=1-633c7675-000000000000000000000004;Parent=0000000000000005;Sampled=0;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", - "user keep 5->6 | 5 | 6 | PrioritySampling.USER_KEEP | 'Root=1-633c7675-000000000000000000000005;Parent=0000000000000006;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", - "user drop 6->7 | 6 | 7 | PrioritySampling.USER_DROP | 'Root=1-633c7675-000000000000000000000006;Parent=0000000000000007;Sampled=0;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", - "unset max->max-1 | 18446744073709551615 | 18446744073709551614 | PrioritySampling.UNSET | 'Root=1-633c7675-00000000ffffffffffffffff;Parent=fffffffffffffffe;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v' ", - "keep max-1->max | 18446744073709551614 | 18446744073709551615 | PrioritySampling.SAMPLER_KEEP | 'Root=1-633c7675-00000000fffffffffffffffe;Parent=ffffffffffffffff;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'" + "scenario | traceId | spanId | samplingPriority | expectedTraceHeader ", + "unset 1->2 | 1 | 2 | PrioritySampling.UNSET | 'Root=1-633c7675-000000000000000000000001;Parent=0000000000000002;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v' ", + "keep 2->3 | 2 | 3 | PrioritySampling.SAMPLER_KEEP | 'Root=1-633c7675-000000000000000000000002;Parent=0000000000000003;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", + "drop 4->5 | 4 | 5 | PrioritySampling.SAMPLER_DROP | 'Root=1-633c7675-000000000000000000000004;Parent=0000000000000005;Sampled=0;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", + "user keep 5->6 | 5 | 6 | PrioritySampling.USER_KEEP | 'Root=1-633c7675-000000000000000000000005;Parent=0000000000000006;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", + "user drop 6->7 | 6 | 7 | PrioritySampling.USER_DROP | 'Root=1-633c7675-000000000000000000000006;Parent=0000000000000007;Sampled=0;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'", + "unset max->max-1 | TRACE_ID_MAX | TRACE_ID_MAX-1 | PrioritySampling.UNSET | 'Root=1-633c7675-00000000ffffffffffffffff;Parent=fffffffffffffffe;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v' ", + "keep max-1->max | TRACE_ID_MAX-1 | TRACE_ID_MAX | PrioritySampling.SAMPLER_KEEP | 'Root=1-633c7675-00000000fffffffffffffffe;Parent=ffffffffffffffff;Sampled=1;_dd.origin=fakeOrigin;SOME_CUSTOM_HEADER=some-value;k=v'" }) @SuppressWarnings("unchecked") void injectHttpHeaders( - String traceId, - String spanId, + @ConvertWith(TraceIdConverter.class) String traceId, + @ConvertWith(TraceIdConverter.class) String spanId, @ConvertWith(PrioritySamplingConverter.class) byte samplingPriority, String expectedTraceHeader) { ListWriter writer = new ListWriter(); @@ -74,7 +76,7 @@ void injectHttpHeaders( Map carrier = mock(Map.class); clearInvocations(timeSource); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); verify(timeSource).getCurrentTimeMillis(); verify(carrier).put("X-Amzn-Trace-Id", expectedTraceHeader); @@ -105,7 +107,7 @@ void injectHttpHeadersWithExtractedOriginal( .timeSource(timeSource) .build(); Map headers = - singletonMap( + headers( "X-Amzn-Trace-Id", "Root=1-00000000-00000000" + padLeft(traceId, 16, '0') @@ -125,7 +127,7 @@ void injectHttpHeadersWithExtractedOriginal( Map carrier = mock(Map.class); clearInvocations(timeSource); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); verify(timeSource).getCurrentTimeMillis(); verify(carrier).put("X-Amzn-Trace-Id", expectedTraceHeader); @@ -159,7 +161,7 @@ void injectHttpHeadersWithEndToEnd() { Map carrier = mock(Map.class); mockedContext.beginEndToEnd(); - injector.inject(mockedContext, carrier, MapSetter.INSTANCE); + injector.inject(mockedContext, carrier, Map::put); // 2 calls: CoreTracer constructor + beginEndToEnd() verify(timeSource, times(2)).getCurrentTimeNanos(); diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 383dea205d2..9a62f644004 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -131,6 +131,7 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_PERF_METRICS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PRIORITY_SAMPLING_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PRIORITY_SAMPLING_FORCE; +import static datadog.trace.api.ConfigDefaults.DEFAULT_PROPAGATION_B3_PADDING_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PROPAGATION_STYLE; import static datadog.trace.api.ConfigDefaults.DEFAULT_REMOTE_CONFIG_ENABLED; @@ -1840,7 +1841,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins DEFAULT_PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED); tracePropagationStyleB3PaddingEnabled = - isEnabled(true, TRACE_PROPAGATION_STYLE, ".b3.padding.enabled"); + isEnabled( + DEFAULT_PROPAGATION_B3_PADDING_ENABLED, TRACE_PROPAGATION_STYLE, ".b3.padding.enabled"); TracePropagationBehaviorExtract tmpTracePropagationBehaviorExtract; try { diff --git a/utils/junit-utils/src/main/java/datadog/trace/junit/utils/tabletest/TraceIdConverter.java b/utils/junit-utils/src/main/java/datadog/trace/junit/utils/tabletest/TraceIdConverter.java new file mode 100644 index 00000000000..00dce0b20ea --- /dev/null +++ b/utils/junit-utils/src/main/java/datadog/trace/junit/utils/tabletest/TraceIdConverter.java @@ -0,0 +1,46 @@ +package datadog.trace.junit.utils.tabletest; + +import static java.math.BigInteger.ONE; + +import java.math.BigInteger; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; + +/** + * Converts symbolic trace/span ID names to their decimal string representation. + * + *

Supported names: + * + *

    + *
  • {@code TRACE_ID_MAX} — max unsigned 64-bit value (18446744073709551615 = 2⁶⁴ − 1) + *
  • {@code TRACE_ID_MAX-1} — max minus one (18446744073709551614 = 2⁶⁴ − 2) + *
  • {@code TRACE_ID_MAX+1} — first out-of-range value (18446744073709551616 = 2⁶⁴) + *
+ * + *

All other values are passed through unchanged. + */ +public class TraceIdConverter implements ArgumentConverter { + // 2^64 - 1 + public static final String TRACE_ID_MAX = Long.toUnsignedString(-1L); + // 2^64 - 2 + public static final String TRACE_ID_MAX_MINUS_1 = Long.toUnsignedString(-2L); + // 2^64 (first out-of-range value) + public static final String TRACE_ID_MAX_PLUS_1 = new BigInteger(TRACE_ID_MAX).add(ONE).toString(); + + @Override + public Object convert(Object source, ParameterContext context) + throws ArgumentConversionException { + if (source == null) return null; + switch (source.toString()) { + case "TRACE_ID_MAX": + return TRACE_ID_MAX; + case "TRACE_ID_MAX-1": + return TRACE_ID_MAX_MINUS_1; + case "TRACE_ID_MAX+1": + return TRACE_ID_MAX_PLUS_1; + default: + return source.toString(); + } + } +} diff --git a/utils/test-utils/src/main/groovy/datadog/trace/test/util/StringUtils.groovy b/utils/test-utils/src/main/groovy/datadog/trace/test/util/StringUtils.groovy deleted file mode 100644 index 6b1b4c0c00a..00000000000 --- a/utils/test-utils/src/main/groovy/datadog/trace/test/util/StringUtils.groovy +++ /dev/null @@ -1,25 +0,0 @@ -package datadog.trace.test.util - -class StringUtils { - - static String padHexLower(String hex, int size) { - hex = hex.toLowerCase(Locale.ROOT) - int left = size - hex.length() - if (size > 0) { - return "${'0' * left}${hex}" - } - return hex - } - - static String trimHex(String hex) { - int length = hex.length() - int i = 0 - while (i < length && hex.charAt(i) == '0') { - i++ - } - if (i == length) { - return "0" - } - return hex.substring(i, length) - } -} diff --git a/utils/test-utils/src/main/java/datadog/trace/test/util/JavaStringUtils.java b/utils/test-utils/src/main/java/datadog/trace/test/util/JavaStringUtils.java deleted file mode 100644 index 5a1c91d050e..00000000000 --- a/utils/test-utils/src/main/java/datadog/trace/test/util/JavaStringUtils.java +++ /dev/null @@ -1,38 +0,0 @@ -package datadog.trace.test.util; - -import java.util.Locale; - -/** - * Java port of {@link StringUtils}. Will replace {@code StringUtils.groovy} once all Groovy callers - * have been migrated to Java. - */ -public final class JavaStringUtils { - - private JavaStringUtils() {} - - public static String padHexLower(String hex, int size) { - String lower = hex.toLowerCase(Locale.ROOT); - int diff = size - lower.length(); - if (size <= 0 || diff <= 0) { - return lower; - } - StringBuilder sb = new StringBuilder(size); - for (int i = 0; i < diff; i++) { - sb.append('0'); - } - sb.append(lower); - return sb.toString(); - } - - public static String trimHex(String hex) { - int length = hex.length(); - int firstNonZero = 0; - while (firstNonZero < length && hex.charAt(firstNonZero) == '0') { - firstNonZero++; - } - if (firstNonZero == length) { - return "0"; - } - return hex.substring(firstNonZero, length); - } -}