Ensure headers are never null

Null tracer version results in the request being rejected by the agent.

Also make the DDSpanBuilderTest.shouldBuildSpanTimestampInNano more reliable.
This commit is contained in:
Tyler Benson 2017-07-07 16:17:08 -07:00
parent 586c7eab0c
commit dcdf6deb64
6 changed files with 41 additions and 32 deletions

View File

@ -37,3 +37,7 @@ test {
}
test.dependsOn project(':dd-java-agent').shadowJar
parent.subprojects.collect { it.tasks.withType(Test) } each {
test.shouldRunAfter it
}

View File

@ -1,4 +1,5 @@
plugins {
id 'groovy'
id "com.github.johnrengelman.shadow" version "2.0.1"
}

View File

@ -22,8 +22,13 @@ import java.util.*;
*/
public class DDTracer implements io.opentracing.Tracer {
public final static String CURRENT_VERSION = DDTracer.class.getPackage().getImplementationVersion();
public final static String JAVA_VERSION = System.getProperty("java.version", "unknown");
public final static String CURRENT_VERSION;
static {
String version = DDTracer.class.getPackage().getImplementationVersion();
CURRENT_VERSION = version != null ? version : "unknown";
}
/**
* Writer is an charge of reporting traces and spans to the desired endpoint

View File

@ -1,7 +1,4 @@
package com.datadog.trace
import com.datadoghq.trace.DDSpan
import com.datadoghq.trace.DDSpanContext
package com.datadoghq.trace
class SpanFactory {
static def newSpanOf(long timestampMicro) {

View File

@ -1,10 +1,10 @@
package com.datadoghq.trace.writer
import com.datadog.trace.SpanFactory
import com.datadoghq.trace.DDSpan
import com.datadoghq.trace.SpanFactory
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import ratpack.http.Headers
import ratpack.http.MediaType
import spock.lang.AutoCleanup
import spock.lang.Specification
import java.util.concurrent.atomic.AtomicReference
@ -54,11 +54,13 @@ class DDApiTest extends Specification {
def "content is sent as JSON"() {
setup:
def requestContentType = new AtomicReference<MediaType>()
def requestHeaders = new AtomicReference<Headers>()
def requestBody = new AtomicReference<String>()
def agent = ratpack {
handlers {
put("v0.3/traces") {
requestContentType.set(request.contentType)
requestHeaders.set(request.headers)
request.body.then {
requestBody.set(it.text)
response.send()
@ -71,47 +73,47 @@ class DDApiTest extends Specification {
expect:
client.sendTraces(traces)
requestContentType.get().type == APPLICATION_JSON
areEqual(requestBody.get(), expectedRequestBody)
requestHeaders.get().get("Datadog-Meta-Lang") == "java"
requestHeaders.get().get("Datadog-Meta-Lang-Version") == System.getProperty("java.version", "unknown");
requestHeaders.get().get("Datadog-Meta-Tracer-Version") == "unknown"
convert(requestBody.get()) == expectedRequestBody
cleanup:
agent.close()
// Populate thread info dynamically as it is different when run via gradle vs idea.
where:
traces | expectedRequestBody
[] | '[]'
[SpanFactory.newSpanOf(1L)] | '''[{
traces | expectedRequestBody
[] | []
[SpanFactory.newSpanOf(1L)] | [new TreeMap<>([
"duration":0,
"error":0,
"meta":{"thread-name":"main","thread-id":"1"},
"meta":["thread-name":Thread.currentThread().getName(),"thread-id":"${Thread.currentThread().id}"],
"name":"fakeOperation",
"parent_id":0,
"resource":"fakeResource"
"resource":"fakeResource",
"service":"fakeService",
"span_id":1,
"start":1000,
"trace_id":1,
"type":"fakeType",
}]'''
[SpanFactory.newSpanOf(100L)] | '''[{
"type":"fakeType"
])]
[SpanFactory.newSpanOf(100L)] | [new TreeMap<>([
"duration":0,
"error":0,
"meta":{"thread-name":"main","thread-id":"1"},
"meta":["thread-name":Thread.currentThread().getName(),"thread-id":"${Thread.currentThread().id}"],
"name":"fakeOperation",
"parent_id":0,
"resource":"fakeResource"
"resource":"fakeResource",
"service":"fakeService",
"span_id":1,
"start":100000,
"trace_id":1,
"type":"fakeType",
}]'''
"type":"fakeType"
])]
}
static void areEqual(String json1, String json2) {
def tree1 = mapper.readTree json1
def tree2 = mapper.readTree json2
assert tree1.equals(tree2)
static List<TreeMap<String, Object>> convert(String json) {
return mapper.readValue(json, new TypeReference<List<TreeMap<String, Object>>>() {})
}
}

View File

@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -124,15 +125,14 @@ public class DDSpanBuilderTest {
assertThat(span.getStartTime()).isEqualTo(expectedTimestamp * 1000L);
// auto-timestamp in nanoseconds
long tick = System.currentTimeMillis() * 1000 * 1000L;
long tick = System.currentTimeMillis();
span = tracer
.buildSpan(expectedName)
.withServiceName("foo")
.start();
// between now and now + 100ms
assertThat(span.getStartTime()).isBetween(tick, tick + 100 * 1000L);
// Give a range of +/- 2 millis
assertThat(span.getStartTime()).isBetween(MILLISECONDS.toNanos(tick - 2), MILLISECONDS.toNanos(tick + 2));
}
@ -143,7 +143,7 @@ public class DDSpanBuilderTest {
final long expectedParentId = spanId;
DDSpanContext mockedContext = mock(DDSpanContext.class);
when(mockedContext.getSpanId()).thenReturn(spanId);
when(mockedContext.getServiceName()).thenReturn("foo");