Move DDApi and rename to DDAgentApi

Reduce visibility back to what it was before refactoring.
This commit is contained in:
Tyler Benson 2019-12-20 14:36:45 -08:00
parent 84f9d80258
commit 24e2fe6da7
12 changed files with 82 additions and 76 deletions

View File

@ -14,8 +14,8 @@ import datadog.trace.api.sampling.PrioritySampling;
import datadog.trace.common.sampling.PrioritySampler;
import datadog.trace.common.sampling.Sampler;
import datadog.trace.common.writer.DDAgentWriter;
import datadog.trace.common.writer.DDApi;
import datadog.trace.common.writer.Writer;
import datadog.trace.common.writer.ddagent.DDAgentApi;
import datadog.trace.context.ScopeListener;
import io.opentracing.References;
import io.opentracing.Scope;
@ -246,9 +246,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
extractor = HttpCodec.createExtractor(Config.get(), taggedHeaders);
if (this.writer instanceof DDAgentWriter) {
final DDApi api = ((DDAgentWriter) this.writer).getApi();
if (sampler instanceof DDApi.ResponseListener) {
api.addResponseListener((DDApi.ResponseListener) this.sampler);
final DDAgentApi api = ((DDAgentWriter) this.writer).getApi();
if (sampler instanceof DDAgentApi.ResponseListener) {
api.addResponseListener((DDAgentApi.ResponseListener) this.sampler);
}
}

View File

@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import datadog.opentracing.DDSpan;
import datadog.trace.api.sampling.PrioritySampling;
import datadog.trace.common.writer.DDApi.ResponseListener;
import datadog.trace.common.writer.ddagent.DDAgentApi.ResponseListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

View File

@ -7,6 +7,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import datadog.opentracing.DDSpan;
import datadog.trace.common.util.DaemonThreadFactory;
import datadog.trace.common.writer.ddagent.DDAgentApi;
import datadog.trace.common.writer.ddagent.Monitor;
import datadog.trace.common.writer.ddagent.TraceConsumer;
import datadog.trace.common.writer.ddagent.TraceSerializingDisruptor;
@ -34,7 +35,7 @@ public class DDAgentWriter implements Writer {
private static final ThreadFactory SCHEDULED_FLUSH_THREAD_FACTORY =
new DaemonThreadFactory("dd-trace-writer");
private final DDApi api;
private final DDAgentApi api;
public final int flushFrequencySeconds;
public final TraceSerializingDisruptor disruptor;
@ -46,16 +47,17 @@ public class DDAgentWriter implements Writer {
public DDAgentWriter() {
this(
new DDApi(DEFAULT_AGENT_HOST, DEFAULT_TRACE_AGENT_PORT, DEFAULT_AGENT_UNIX_DOMAIN_SOCKET),
new DDAgentApi(
DEFAULT_AGENT_HOST, DEFAULT_TRACE_AGENT_PORT, DEFAULT_AGENT_UNIX_DOMAIN_SOCKET),
new Monitor.Noop());
}
public DDAgentWriter(final DDApi api, final Monitor monitor) {
public DDAgentWriter(final DDAgentApi api, final Monitor monitor) {
this(api, monitor, DISRUPTOR_BUFFER_SIZE, SENDER_QUEUE_SIZE, FLUSH_PAYLOAD_DELAY);
}
/** Old signature (pre-Monitor) used in tests */
private DDAgentWriter(final DDApi api) {
private DDAgentWriter(final DDAgentApi api) {
this(api, new Monitor.Noop());
}
@ -67,7 +69,7 @@ public class DDAgentWriter implements Writer {
* @param flushFrequencySeconds value < 1 disables scheduled flushes
*/
private DDAgentWriter(
final DDApi api,
final DDAgentApi api,
final int disruptorSize,
final int senderQueueSize,
final int flushFrequencySeconds) {
@ -76,7 +78,7 @@ public class DDAgentWriter implements Writer {
// DQH - TODO - Update the tests & remove this
private DDAgentWriter(
final DDApi api,
final DDAgentApi api,
final Monitor monitor,
final int disruptorSize,
final int flushFrequencySeconds) {
@ -84,12 +86,13 @@ public class DDAgentWriter implements Writer {
}
// DQH - TODO - Update the tests & remove this
private DDAgentWriter(final DDApi api, final int disruptorSize, final int flushFrequencySeconds) {
private DDAgentWriter(
final DDAgentApi api, final int disruptorSize, final int flushFrequencySeconds) {
this(api, new Monitor.Noop(), disruptorSize, SENDER_QUEUE_SIZE, flushFrequencySeconds);
}
private DDAgentWriter(
final DDApi api,
final DDAgentApi api,
final Monitor monitor,
final int disruptorSize,
final int senderQueueSize,
@ -147,7 +150,7 @@ public class DDAgentWriter implements Writer {
traceCount.incrementAndGet();
}
public DDApi getApi() {
public DDAgentApi getApi() {
return api;
}

View File

@ -2,6 +2,7 @@ package datadog.trace.common.writer;
import datadog.opentracing.DDSpan;
import datadog.trace.api.Config;
import datadog.trace.common.writer.ddagent.DDAgentApi;
import datadog.trace.common.writer.ddagent.Monitor;
import java.io.Closeable;
import java.util.List;
@ -66,8 +67,8 @@ public interface Writer extends Closeable {
return new DDAgentWriter(createApi(config), createMonitor(config));
}
private static DDApi createApi(final Config config) {
return new DDApi(
private static DDAgentApi createApi(final Config config) {
return new DDAgentApi(
config.getAgentHost(), config.getAgentPort(), config.getAgentUnixDomainSocket());
}

View File

@ -1,4 +1,4 @@
package datadog.trace.common.writer;
package datadog.trace.common.writer.ddagent;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
@ -28,7 +28,7 @@ import org.msgpack.jackson.dataformat.MessagePackFactory;
/** The API pointing to a DD agent */
@Slf4j
public class DDApi {
public class DDAgentApi {
private static final String DATADOG_META_LANG = "Datadog-Meta-Lang";
private static final String DATADOG_META_LANG_VERSION = "Datadog-Meta-Lang-Version";
private static final String DATADOG_META_LANG_INTERPRETER = "Datadog-Meta-Lang-Interpreter";
@ -53,7 +53,7 @@ public class DDApi {
private final OkHttpClient httpClient;
private final HttpUrl tracesUrl;
public DDApi(final String host, final int port, final String unixDomainSocketPath) {
public DDAgentApi(final String host, final int port, final String unixDomainSocketPath) {
this(
host,
port,
@ -61,7 +61,7 @@ public class DDApi {
unixDomainSocketPath);
}
DDApi(
DDAgentApi(
final String host,
final int port,
final boolean v4EndpointsAvailable,
@ -89,7 +89,7 @@ public class DDApi {
* @return a Response object -- encapsulating success of communication, sending, and result
* parsing
*/
public Response sendTraces(final List<List<DDSpan>> traces) {
Response sendTraces(final List<List<DDSpan>> traces) {
final List<byte[]> serializedTraces = new ArrayList<>(traces.size());
int sizeInBytes = 0;
for (final List<DDSpan> trace : traces) {
@ -107,11 +107,11 @@ public class DDApi {
return sendSerializedTraces(serializedTraces.size(), sizeInBytes, serializedTraces);
}
public byte[] serializeTrace(final List<DDSpan> trace) throws JsonProcessingException {
byte[] serializeTrace(final List<DDSpan> trace) throws JsonProcessingException {
return OBJECT_MAPPER.writeValueAsBytes(trace);
}
public Response sendSerializedTraces(
Response sendSerializedTraces(
final int representativeCount, final Integer sizeInBytes, final List<byte[]> traces) {
try {
final RequestBody body =

View File

@ -6,19 +6,22 @@ import com.lmax.disruptor.EventTranslatorOneArg;
import datadog.opentracing.DDSpan;
import java.util.List;
public class DisruptorEvent<T> {
class DisruptorEvent<T> {
public volatile boolean shouldFlush = false;
public volatile T data = null;
public static class Factory<T> implements EventFactory<DisruptorEvent<T>> {
static class Factory<T> implements EventFactory<DisruptorEvent<T>> {
@Override
public DisruptorEvent<T> newInstance() {
return new DisruptorEvent<>();
}
}
public static class TraceTranslator
static class TraceTranslator
implements EventTranslatorOneArg<DisruptorEvent<List<DDSpan>>, List<DDSpan>> {
static final DisruptorEvent.TraceTranslator TRACE_TRANSLATOR =
new DisruptorEvent.TraceTranslator();
@Override
public void translateTo(
final DisruptorEvent<List<DDSpan>> event, final long sequence, final List<DDSpan> trace) {
@ -26,7 +29,10 @@ public class DisruptorEvent<T> {
}
}
public static class FlushTranslator implements EventTranslator<DisruptorEvent<List<DDSpan>>> {
static class FlushTranslator implements EventTranslator<DisruptorEvent<List<DDSpan>>> {
static final DisruptorEvent.FlushTranslator FLUSH_TRANSLATOR =
new DisruptorEvent.FlushTranslator();
@Override
public void translateTo(final DisruptorEvent<List<DDSpan>> event, final long sequence) {
event.shouldFlush = true;

View File

@ -5,7 +5,6 @@ import com.timgroup.statsd.StatsDClient;
import datadog.opentracing.DDSpan;
import datadog.opentracing.DDTraceOTInfo;
import datadog.trace.common.writer.DDAgentWriter;
import datadog.trace.common.writer.DDApi;
import java.util.List;
/**
@ -43,13 +42,13 @@ public interface Monitor {
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response);
final DDAgentApi.Response response);
void onFailedSend(
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response);
final DDAgentApi.Response response);
final class StatsD implements Monitor {
public static final String PREFIX = "datadog.tracer";
@ -138,7 +137,7 @@ public interface Monitor {
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response) {
final DDAgentApi.Response response) {
onSendAttempt(agentWriter, representativeCount, sizeInBytes, response);
}
@ -147,7 +146,7 @@ public interface Monitor {
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response) {
final DDAgentApi.Response response) {
onSendAttempt(agentWriter, representativeCount, sizeInBytes, response);
}
@ -155,7 +154,7 @@ public interface Monitor {
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response) {
final DDAgentApi.Response response) {
statsd.incrementCounter("api.requests");
statsd.recordGaugeValue("queue.length", representativeCount);
// TODO: missing queue.spans (# of spans being sent)
@ -215,14 +214,14 @@ public interface Monitor {
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response) {}
final DDAgentApi.Response response) {}
@Override
public void onFailedSend(
final DDAgentWriter agentWriter,
final int representativeCount,
final int sizeInBytes,
final DDApi.Response response) {}
final DDAgentApi.Response response) {}
@Override
public String toString() {

View File

@ -4,7 +4,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.lmax.disruptor.EventHandler;
import datadog.opentracing.DDSpan;
import datadog.trace.common.writer.DDAgentWriter;
import datadog.trace.common.writer.DDApi;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
@ -74,7 +73,7 @@ public class TraceConsumer implements EventHandler<DisruptorEvent<List<DDSpan>>>
}
if (writer.scheduledWriterExecutor.isShutdown()) {
writer.monitor.onFailedSend(
writer, traceCount.get(), payloadSize, DDApi.Response.failed(-1));
writer, traceCount.get(), payloadSize, DDAgentApi.Response.failed(-1));
writer.apiPhaser.arrive(); // Allow flush to return
return;
}
@ -93,7 +92,7 @@ public class TraceConsumer implements EventHandler<DisruptorEvent<List<DDSpan>>>
senderSemaphore.acquire();
} catch (final InterruptedException e) {
writer.monitor.onFailedSend(
writer, representativeCount, sizeInBytes, DDApi.Response.failed(e));
writer, representativeCount, sizeInBytes, DDAgentApi.Response.failed(e));
// Finally, we'll schedule another flush
// Any threads awaiting the flush will continue to wait
@ -106,7 +105,7 @@ public class TraceConsumer implements EventHandler<DisruptorEvent<List<DDSpan>>>
senderSemaphore.release();
try {
final DDApi.Response response =
final DDAgentApi.Response response =
writer
.getApi()
.sendSerializedTraces(representativeCount, sizeInBytes, toSend);
@ -132,7 +131,7 @@ public class TraceConsumer implements EventHandler<DisruptorEvent<List<DDSpan>>>
// However, just to be safe to start, create a failed Response to handle any
// spurious Throwable-s.
writer.monitor.onFailedSend(
writer, representativeCount, sizeInBytes, DDApi.Response.failed(e));
writer, representativeCount, sizeInBytes, DDAgentApi.Response.failed(e));
} finally {
writer.apiPhaser.arrive(); // Flush completed.
}
@ -140,7 +139,7 @@ public class TraceConsumer implements EventHandler<DisruptorEvent<List<DDSpan>>>
});
} catch (final RejectedExecutionException ex) {
writer.monitor.onFailedSend(
writer, representativeCount, sizeInBytes, DDApi.Response.failed(ex));
writer, representativeCount, sizeInBytes, DDAgentApi.Response.failed(ex));
writer.apiPhaser.arrive(); // Allow flush to return
}
} finally {

View File

@ -1,5 +1,7 @@
package datadog.trace.common.writer.ddagent;
import static datadog.trace.common.writer.ddagent.DisruptorEvent.FlushTranslator.FLUSH_TRANSLATOR;
import static datadog.trace.common.writer.ddagent.DisruptorEvent.TraceTranslator.TRACE_TRANSLATOR;
import static java.util.concurrent.TimeUnit.SECONDS;
import com.lmax.disruptor.SleepingWaitStrategy;
@ -20,10 +22,6 @@ import lombok.extern.slf4j.Slf4j;
public class TraceSerializingDisruptor implements Closeable {
private static final ThreadFactory DISRUPTOR_THREAD_FACTORY =
new DaemonThreadFactory("dd-trace-disruptor");
private static final DisruptorEvent.TraceTranslator TRACE_TRANSLATOR =
new DisruptorEvent.TraceTranslator();
private static final DisruptorEvent.FlushTranslator FLUSH_TRANSLATOR =
new DisruptorEvent.FlushTranslator();
private final FlushTask flushTask = new FlushTask();
private final Disruptor<DisruptorEvent<List<DDSpan>>> disruptor;

View File

@ -3,8 +3,8 @@ package datadog.trace.api.writer
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.JsonNode
import datadog.opentracing.SpanFactory
import datadog.trace.common.writer.DDApi
import datadog.trace.common.writer.DDApi.ResponseListener
import datadog.trace.common.writer.ddagent.DDAgentApi
import datadog.trace.common.writer.ddagent.DDAgentApi.ResponseListener
import datadog.trace.util.test.DDSpecification
import java.util.concurrent.atomic.AtomicLong
@ -12,8 +12,8 @@ import java.util.concurrent.atomic.AtomicReference
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
class DDApiTest extends DDSpecification {
static mapper = DDApi.OBJECT_MAPPER
class DDAgentApiTest extends DDSpecification {
static mapper = DDAgentApi.OBJECT_MAPPER
def "sending an empty list of traces returns no errors"() {
setup:
@ -30,7 +30,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", agent.address.port, null)
def client = new DDAgentApi("localhost", agent.address.port, null)
expect:
client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.4/traces"
@ -51,7 +51,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", agent.address.port, null)
def client = new DDAgentApi("localhost", agent.address.port, null)
expect:
client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.3/traces"
@ -73,7 +73,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", agent.address.port, null)
def client = new DDAgentApi("localhost", agent.address.port, null)
expect:
client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.4/traces"
@ -136,7 +136,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", agent.address.port, null)
def client = new DDAgentApi("localhost", agent.address.port, null)
client.addResponseListener(responseListener)
when:
@ -162,7 +162,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", v3Agent.address.port, null)
def client = new DDAgentApi("localhost", v3Agent.address.port, null)
expect:
client.tracesUrl.toString() == "http://localhost:${v3Agent.address.port}/v0.3/traces"
@ -189,7 +189,7 @@ class DDApiTest extends DDSpecification {
}
}
def port = badPort ? 999 : agent.address.port
def client = new DDApi("localhost", port, null)
def client = new DDAgentApi("localhost", port, null)
expect:
client.tracesUrl.toString() == "http://localhost:${port}/$endpointVersion/traces"
@ -216,7 +216,7 @@ class DDApiTest extends DDSpecification {
}
}
}
def client = new DDApi("localhost", agent.address.port, null)
def client = new DDAgentApi("localhost", agent.address.port, null)
when:
def success = client.sendTraces(traces).success()

View File

@ -7,7 +7,7 @@ import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.DDAgentWriter
import datadog.trace.common.writer.DDApi
import datadog.trace.common.writer.ddagent.DDAgentApi
import datadog.trace.common.writer.ddagent.Monitor
import datadog.trace.common.writer.ddagent.TraceConsumer
import datadog.trace.util.test.DDSpecification
@ -24,7 +24,7 @@ import static datadog.trace.common.writer.DDAgentWriter.DISRUPTOR_BUFFER_SIZE
@Timeout(20)
class DDAgentWriterTest extends DDSpecification {
def api = Mock(DDApi)
def api = Mock(DDAgentApi)
def "test happy path"() {
setup:
@ -180,7 +180,7 @@ class DDAgentWriterTest extends DDSpecification {
Mock(DDTracer))
minimalSpan = new DDSpan(0, minimalContext)
minimalTrace = [minimalSpan]
traceSize = DDApi.OBJECT_MAPPER.writeValueAsBytes(minimalTrace).length
traceSize = DDAgentApi.OBJECT_MAPPER.writeValueAsBytes(minimalTrace).length
maxedPayloadTraceCount = ((int) (TraceConsumer.FLUSH_PAYLOAD_BYTES / traceSize)) + 1
}
@ -253,7 +253,7 @@ class DDAgentWriterTest extends DDSpecification {
}
}
}
def api = new DDApi("localhost", agent.address.port, null)
def api = new DDAgentApi("localhost", agent.address.port, null)
def monitor = Mock(Monitor)
def writer = new DDAgentWriter(api, monitor)
@ -302,7 +302,7 @@ class DDAgentWriterTest extends DDSpecification {
}
}
}
def api = new DDApi("localhost", agent.address.port, null)
def api = new DDAgentApi("localhost", agent.address.port, null)
def monitor = Mock(Monitor)
def writer = new DDAgentWriter(api, monitor)
@ -336,13 +336,13 @@ class DDAgentWriterTest extends DDSpecification {
setup:
def minimalTrace = createMinimalTrace()
def api = new DDApi("localhost", 8192, null) {
DDApi.Response sendSerializedTraces(
def api = new DDAgentApi("localhost", 8192, null) {
DDAgentApi.Response sendSerializedTraces(
int representativeCount,
Integer sizeInBytes,
List<byte[]> traces) {
// simulating a communication failure to a server
return DDApi.Response.failed(new IOException("comm error"))
return DDAgentApi.Response.failed(new IOException("comm error"))
}
}
def monitor = Mock(Monitor)
@ -400,7 +400,7 @@ class DDAgentWriterTest extends DDSpecification {
}
}
}
def api = new DDApi("localhost", agent.address.port, null)
def api = new DDAgentApi("localhost", agent.address.port, null)
// This test focuses just on failed publish, so not verifying every callback
def monitor = Stub(Monitor)
@ -505,7 +505,7 @@ class DDAgentWriterTest extends DDSpecification {
}
}
}
def api = new DDApi("localhost", agent.address.port, null)
def api = new DDAgentApi("localhost", agent.address.port, null)
// This test focuses just on failed publish, so not verifying every callback
def monitor = Stub(Monitor)
@ -566,7 +566,7 @@ class DDAgentWriterTest extends DDSpecification {
}
}
}
def api = new DDApi("localhost", agent.address.port, null)
def api = new DDAgentApi("localhost", agent.address.port, null)
def statsd = Stub(StatsDClient)
statsd.incrementCounter("queue.accepted") >> { stat ->
@ -606,13 +606,13 @@ class DDAgentWriterTest extends DDSpecification {
def minimalTrace = createMinimalTrace()
// DQH -- need to set-up a dummy agent for the final send callback to work
def api = new DDApi("localhost", 8192, null) {
DDApi.Response sendSerializedTraces(
def api = new DDAgentApi("localhost", 8192, null) {
DDAgentApi.Response sendSerializedTraces(
int representativeCount,
Integer sizeInBytes,
List<byte[]> traces) {
// simulating a communication failure to a server
return DDApi.Response.failed(new IOException("comm error"))
return DDAgentApi.Response.failed(new IOException("comm error"))
}
}

View File

@ -4,8 +4,8 @@ import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.DDApi
import datadog.trace.common.writer.ListWriter
import datadog.trace.common.writer.ddagent.DDAgentApi
import datadog.trace.util.test.DDSpecification
import org.testcontainers.containers.GenericContainer
import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy
@ -20,7 +20,7 @@ class DDApiIntegrationTest {
// Do not run tests locally on Java7 since testcontainers are not compatible with Java7
// It is fine to run on CI because CI provides rabbitmq externally, not through testcontainers
@Requires({ "true" == System.getenv("CI") || jvm.java8Compatible })
static class DDApiIntegrationV4Test extends DDSpecification {
static class DDAgentApiIntegrationV4Test extends DDSpecification {
static final WRITER = new ListWriter()
static final TRACER = new DDTracer(WRITER)
static final CONTEXT = new DDSpanContext(
@ -64,7 +64,7 @@ class DDApiIntegrationTest {
def endpoint = new AtomicReference<String>(null)
def agentResponse = new AtomicReference<String>(null)
DDApi.ResponseListener responseListener = { String receivedEndpoint, JsonNode responseJson ->
DDAgentApi.ResponseListener responseListener = { String receivedEndpoint, JsonNode responseJson ->
endpoint.set(receivedEndpoint)
agentResponse.set(responseJson.toString())
}
@ -109,10 +109,10 @@ class DDApiIntegrationTest {
}
def setup() {
api = new DDApi(agentContainerHost, agentContainerPort, v4(), null)
api = new DDAgentApi(agentContainerHost, agentContainerPort, v4(), null)
api.addResponseListener(responseListener)
unixDomainSocketApi = new DDApi(SOMEHOST, SOMEPORT, v4(), socketPath.toString())
unixDomainSocketApi = new DDAgentApi(SOMEHOST, SOMEPORT, v4(), socketPath.toString())
unixDomainSocketApi.addResponseListener(responseListener)
}
@ -159,7 +159,7 @@ class DDApiIntegrationTest {
}
@Requires({ "true" == System.getenv("CI") || jvm.java8Compatible })
static class DDApiIntegrationV3Test extends DDApiIntegrationV4Test {
static class DDAgentApiIntegrationV3Test extends DDAgentApiIntegrationV4Test {
boolean v4() {
return false
}