diff --git a/dd-trace/dd-trace.gradle b/dd-trace/dd-trace.gradle index e2bce02818..690fa7223b 100644 --- a/dd-trace/dd-trace.gradle +++ b/dd-trace/dd-trace.gradle @@ -17,8 +17,6 @@ whitelistedInstructionClasses += whitelistedBranchClasses += [ 'com.datadoghq.trace.DDTags', 'com.datadoghq.trace.DDTraceInfo', 'com.datadoghq.trace.util.Clock', - //TODO: Refactor the class in order to make it more testable - 'com.datadoghq.trace.writer.DDAgentWriter', ] @@ -42,6 +40,8 @@ dependencies { testCompile group: 'org.spockframework', name: 'spock-core', version: '1.0-groovy-2.4' testCompile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.4' testCompile group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.4.6' + testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6' + testCompile group: 'cglib', name: 'cglib-nodep', version: '3.2.5' jmh 'commons-io:commons-io:2.4' } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java index 80f0576378..3b27f6576c 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java @@ -30,13 +30,13 @@ public class DDAgentWriter implements Writer { public static final int DEFAULT_PORT = 8126; /** Maximum number of traces kept in memory */ - private static final int DEFAULT_MAX_TRACES = 1000; + static final int DEFAULT_MAX_TRACES = 1000; /** Timeout for the API in seconds */ - private static final long API_TIMEOUT_SECONDS = 1; + static final long API_TIMEOUT_SECONDS = 1; /** Flush interval for the API in seconds */ - private static final long FLUSH_TIME_SECONDS = 1; + static final long FLUSH_TIME_SECONDS = 1; /** Scheduled thread pool, acting like a cron */ private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1); @@ -57,9 +57,13 @@ public class DDAgentWriter implements Writer { } public DDAgentWriter(final DDApi api) { + this(api, new WriterQueue>>(DEFAULT_MAX_TRACES)); + } + + public DDAgentWriter(final DDApi api, final WriterQueue>> queue) { super(); this.api = api; - traces = new WriterQueue<>(DEFAULT_MAX_TRACES); + traces = queue; } /* (non-Javadoc) @@ -67,7 +71,6 @@ public class DDAgentWriter implements Writer { */ @Override public void write(final List> trace) { - final List> removed = traces.add(trace); if (removed != null && !queueFullReported) { log.debug("Queue is full, traces will be discarded, queue size: {}", DEFAULT_MAX_TRACES); diff --git a/dd-trace/src/test/groovy/com/datadoghq/trace/writer/DDAgentWriterTest.groovy b/dd-trace/src/test/groovy/com/datadoghq/trace/writer/DDAgentWriterTest.groovy new file mode 100644 index 0000000000..a4917b46b3 --- /dev/null +++ b/dd-trace/src/test/groovy/com/datadoghq/trace/writer/DDAgentWriterTest.groovy @@ -0,0 +1,93 @@ +package com.datadoghq.trace.writer + +import com.datadoghq.trace.DDBaseSpan +import spock.lang.Specification + +import static com.datadoghq.trace.SpanFactory.newSpanOf +import static org.mockito.Mockito.mock +import static org.mockito.Mockito.verifyNoMoreInteractions + +class DDAgentWriterTest extends Specification { + + + def "calls to the API are scheduled"() { + + setup: + def api = Mock(DDApi) + def writer = new DDAgentWriter(api) + + when: + writer.start() + Thread.sleep(flush_time_wait) + + then: + 0 * api.sendTraces(_ as List) + + when: + for (def i = 0; i < tick; i++) { + writer.write(trace) + Thread.sleep(flush_time_wait) + } + + then: + tick * api.sendTraces([trace]) + + where: + trace = [newSpanOf(0)] + flush_time_wait = (int) (1.2 * (DDAgentWriter.FLUSH_TIME_SECONDS * 1_000)) + tick << [1, 3] + + + } + + def "check if trace has been added by force"() { + + setup: + def traces = new WriterQueue>>(capacity) + def writer = new DDAgentWriter(Mock(DDApi), traces) + + when: + for (def i = 0; i < capacity; i++) { + writer.write([]) + } + + then: + traces.size() == capacity + + when: + writer.write(trace) + + then: + traces.size() == capacity + traces.getAll().contains(trace) + + where: + trace = [newSpanOf(0)] + capacity = 10 + + + } + + def "check that are no interactions after close"() { + + setup: + def api = mock(DDApi) + def writer = new DDAgentWriter(api) + writer.start() + + when: + writer.close() + writer.write([]) + Thread.sleep(flush_time_wait) + + then: + verifyNoMoreInteractions(api) + + where: + flush_time_wait = (int) (1.2 * (DDAgentWriter.FLUSH_TIME_SECONDS * 1_000)) + + + } + + +}