From 73122ea72c563c9ed4b5b0bd604251be766f250b Mon Sep 17 00:00:00 2001 From: Brian Devins-Suresh Date: Mon, 16 Mar 2020 16:55:31 -0400 Subject: [PATCH] Starting to get tests building --- .../instrumentation/play-2.3/.gitignore | 1 + .../instrumentation/play-2.3/play-2.3.gradle | 47 ++++++++++ .../play24/PlayInstrumentation.java | 52 +++++++++++ .../instrumentation/play24/PlayAdvice.java | 73 ++++++++++++++++ .../instrumentation/play24/PlayHeaders.java | 26 ++++++ .../play24/PlayHttpServerDecorator.java | 86 +++++++++++++++++++ .../play24/RequestCompleteCallback.java | 40 +++++++++ .../groovy/client/PlayWSClientTest.groovy | 54 ++++++++++++ .../NettyServerTestInstrumentation.java | 22 +++++ .../groovy/server/PlayAsyncServerTest.groovy | 46 ++++++++++ .../test/groovy/server/PlayServerTest.groovy | 79 +++++++++++++++++ .../src/test/scala/server/AsyncServer.scala | 5 ++ .../src/test/scala/server/SyncServer.scala | 15 ++++ settings.gradle | 1 + 14 files changed, 547 insertions(+) create mode 100644 dd-java-agent/instrumentation/play-2.3/.gitignore create mode 100644 dd-java-agent/instrumentation/play-2.3/play-2.3.gradle create mode 100644 dd-java-agent/instrumentation/play-2.3/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayAdvice.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHeaders.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/RequestCompleteCallback.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/groovy/client/PlayWSClientTest.groovy create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/NettyServerTestInstrumentation.java create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayAsyncServerTest.groovy create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayServerTest.groovy create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/scala/server/AsyncServer.scala create mode 100644 dd-java-agent/instrumentation/play-2.3/src/test/scala/server/SyncServer.scala diff --git a/dd-java-agent/instrumentation/play-2.3/.gitignore b/dd-java-agent/instrumentation/play-2.3/.gitignore new file mode 100644 index 0000000000..5292519a25 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/.gitignore @@ -0,0 +1 @@ +logs/ \ No newline at end of file diff --git a/dd-java-agent/instrumentation/play-2.3/play-2.3.gradle b/dd-java-agent/instrumentation/play-2.3/play-2.3.gradle new file mode 100644 index 0000000000..e77bad0dea --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/play-2.3.gradle @@ -0,0 +1,47 @@ +ext { + minJavaVersionForTests = JavaVersion.VERSION_1_8 + // Play doesn't work with Java 9+ until 2.6.12 + maxJavaVersionForTests = JavaVersion.VERSION_1_8 +} + +muzzle { + pass { + group = 'com.typesafe.play' + module = 'play_2.11' + versions = '[2.3.0,2.4)' + assertInverse = true + } + fail { + group = 'com.typesafe.play' + module = 'play_2.12' + versions = '[,]' + } + fail { + group = 'com.typesafe.play' + module = 'play_2.13' + versions = '[,]' + } +} + +apply from: "${rootDir}/gradle/java.gradle" +apply from: "${rootDir}/gradle/test-with-scala.gradle" + +apply plugin: 'org.unbroken-dome.test-sets' + +testSets { + latestDepTest { + dirName = 'test' + } +} + +dependencies { + main_java8Compile group: 'com.typesafe.play', name: 'play_2.11', version: '2.3.9' + + testCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.9' + testCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.9' + testCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.9') + + latestDepTestCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.+' + latestDepTestCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.+' + latestDepTestCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.+') +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java b/dd-java-agent/instrumentation/play-2.3/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java new file mode 100644 index 0000000000..fa7d265158 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java @@ -0,0 +1,52 @@ +package datadog.trace.instrumentation.play24; + +import static datadog.trace.agent.tooling.ClassLoaderMatcher.hasClassesNamed; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import java.util.Map; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public final class PlayInstrumentation extends Instrumenter.Default { + + public PlayInstrumentation() { + super("play"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + // Optimization for expensive typeMatcher. + return hasClassesNamed("play.api.mvc.Action"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("play.api.mvc.Action")); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".PlayHttpServerDecorator", + packageName + ".RequestCompleteCallback", + packageName + ".PlayHeaders", + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + named("apply") + .and(takesArgument(0, named("play.api.mvc.Request"))) + .and(returns(named("scala.concurrent.Future"))), + packageName + ".PlayAdvice"); + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayAdvice.java b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayAdvice.java new file mode 100644 index 0000000000..2e495f2e72 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayAdvice.java @@ -0,0 +1,73 @@ +package datadog.trace.instrumentation.play24; + +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; +import static datadog.trace.instrumentation.play24.PlayHeaders.GETTER; +import static datadog.trace.instrumentation.play24.PlayHttpServerDecorator.DECORATE; + +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan.Context; +import datadog.trace.bootstrap.instrumentation.api.Tags; +import net.bytebuddy.asm.Advice; +import play.api.mvc.Action; +import play.api.mvc.Request; +import play.api.mvc.Result; +import scala.concurrent.Future; + +public class PlayAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static AgentScope onEnter(@Advice.Argument(0) final Request req) { + final AgentSpan span; + if (activeSpan() == null) { + final Context extractedContext = propagate().extract(req.headers(), GETTER); + span = startSpan("play.request", extractedContext); + } else { + // An upstream framework (e.g. akka-http, netty) has already started the span. + // Do not extract the context. + span = startSpan("play.request"); + } + DECORATE.afterStart(span); + DECORATE.onConnection(span, req); + + final AgentScope scope = activateSpan(span, false); + scope.setAsyncPropagation(true); + return scope; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopTraceOnResponse( + @Advice.Enter final AgentScope playControllerScope, + @Advice.This final Object thisAction, + @Advice.Thrown final Throwable throwable, + @Advice.Argument(0) final Request req, + @Advice.Return(readOnly = false) final Future responseFuture) { + final AgentSpan playControllerSpan = playControllerScope.span(); + + // Call onRequest on return after tags are populated. + DECORATE.onRequest(playControllerSpan, req); + + if (throwable == null) { + responseFuture.onComplete( + new RequestCompleteCallback(playControllerSpan), + ((Action) thisAction).executionContext()); + } else { + DECORATE.onError(playControllerSpan, throwable); + playControllerSpan.setTag(Tags.HTTP_STATUS, 500); + DECORATE.beforeFinish(playControllerSpan); + playControllerSpan.finish(); + } + playControllerScope.close(); + + final AgentSpan rootSpan = activeSpan(); + // set the resource name on the upstream akka/netty span + DECORATE.onRequest(rootSpan, req); + } + + // Unused method for muzzle to allow only 2.4-2.5 + public static void muzzleCheck() { + play.libs.Akka.system(); + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHeaders.java b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHeaders.java new file mode 100644 index 0000000000..fd8c22ea83 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHeaders.java @@ -0,0 +1,26 @@ +package datadog.trace.instrumentation.play24; + +import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; +import play.api.mvc.Headers; +import scala.Option; +import scala.collection.JavaConversions; + +public class PlayHeaders implements AgentPropagation.Getter { + + public static final PlayHeaders GETTER = new PlayHeaders(); + + @Override + public Iterable keys(final Headers headers) { + return JavaConversions.asJavaIterable(headers.keys()); + } + + @Override + public String get(final Headers headers, final String key) { + final Option option = headers.get(key); + if (option.isDefined()) { + return option.get(); + } else { + return null; + } + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java new file mode 100644 index 0000000000..6c12b2f301 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java @@ -0,0 +1,86 @@ +package datadog.trace.instrumentation.play24; + +import datadog.trace.api.DDTags; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.Tags; +import datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URI; +import java.net.URISyntaxException; +import lombok.extern.slf4j.Slf4j; +import play.api.mvc.Request; +import play.api.mvc.Result; +import scala.Option; + +@Slf4j +public class PlayHttpServerDecorator extends HttpServerDecorator { + public static final PlayHttpServerDecorator DECORATE = new PlayHttpServerDecorator(); + + @Override + protected String[] instrumentationNames() { + return new String[] {"play"}; + } + + @Override + protected String component() { + return "play-action"; + } + + @Override + protected String method(final Request httpRequest) { + return httpRequest.method(); + } + + @Override + protected URI url(final Request request) throws URISyntaxException { + return new URI((request.secure() ? "https://" : "http://") + request.host() + request.uri()); + } + + @Override + protected String peerHostIP(final Request request) { + return request.remoteAddress(); + } + + @Override + protected Integer peerPort(final Request request) { + return null; + } + + @Override + protected Integer status(final Result httpResponse) { + return httpResponse.header().status(); + } + + @Override + public AgentSpan onRequest(final AgentSpan span, final Request request) { + super.onRequest(span, request); + if (request != null) { + // more about routes here: + // https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md#router-tags-are-now-attributes + final Option pathOption = request.tags().get("ROUTE_PATTERN"); + if (!pathOption.isEmpty()) { + final String path = (String) pathOption.get(); + span.setTag(DDTags.RESOURCE_NAME, request.method() + " " + path); + } + } + return span; + } + + @Override + public AgentSpan onError(final AgentSpan span, Throwable throwable) { + span.setTag(Tags.HTTP_STATUS, 500); + if (throwable != null + // This can be moved to instanceof check when using Java 8. + && throwable.getClass().getName().equals("java.util.concurrent.CompletionException") + && throwable.getCause() != null) { + throwable = throwable.getCause(); + } + while ((throwable instanceof InvocationTargetException + || throwable instanceof UndeclaredThrowableException) + && throwable.getCause() != null) { + throwable = throwable.getCause(); + } + return super.onError(span, throwable); + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/RequestCompleteCallback.java b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/RequestCompleteCallback.java new file mode 100644 index 0000000000..cb04d49441 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/main/java8/datadog/trace/instrumentation/play24/RequestCompleteCallback.java @@ -0,0 +1,40 @@ +package datadog.trace.instrumentation.play24; + +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; +import static datadog.trace.instrumentation.play24.PlayHttpServerDecorator.DECORATE; + +import datadog.trace.context.TraceScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import lombok.extern.slf4j.Slf4j; +import play.api.mvc.Result; +import scala.util.Try; + +@Slf4j +public class RequestCompleteCallback extends scala.runtime.AbstractFunction1, Object> { + private final AgentSpan span; + + public RequestCompleteCallback(final AgentSpan span) { + this.span = span; + } + + @Override + public Object apply(final Try result) { + try { + if (result.isFailure()) { + DECORATE.onError(span, result.failed().get()); + } else { + DECORATE.onResponse(span, result.get()); + } + DECORATE.beforeFinish(span); + final TraceScope scope = activeScope(); + if (scope != null) { + scope.setAsyncPropagation(false); + } + } catch (final Throwable t) { + log.debug("error in play instrumentation", t); + } finally { + span.finish(); + } + return null; + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/groovy/client/PlayWSClientTest.groovy b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/client/PlayWSClientTest.groovy new file mode 100644 index 0000000000..f408a5cdc6 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/client/PlayWSClientTest.groovy @@ -0,0 +1,54 @@ +package client + +import datadog.trace.agent.test.base.HttpClientTest +import play.libs.ws.WS +import spock.lang.AutoCleanup +import spock.lang.Shared +import spock.lang.Subject + +import java.util.concurrent.TimeUnit + +// Play 2.6+ uses a separately versioned client that shades the underlying dependency +// This means our built in instrumentation won't work. +class PlayWSClientTest extends HttpClientTest { + @Subject + @Shared + @AutoCleanup + def client = WS.client() + + @Override + int doRequest(String method, URI uri, Map headers, Closure callback) { + def request = client.url(uri.toString()) + headers.entrySet().each { + request.setHeader(it.key, it.value) + } + + def status = request.execute(method).map({ + callback?.call() + it + }).map({ + it.status + }) + return status.get(1, TimeUnit.SECONDS) + } + + @Override + String component() { + return "" // NettyHttpClientDecorator.DECORATE.component() + } + + @Override + String expectedOperationName() { + return "netty.client.request" + } + + @Override + boolean testRedirects() { + false + } + + @Override + boolean testConnectionFailure() { + false + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/NettyServerTestInstrumentation.java b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/NettyServerTestInstrumentation.java new file mode 100644 index 0000000000..61cb150a54 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/NettyServerTestInstrumentation.java @@ -0,0 +1,22 @@ +package server; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.test.base.HttpServerTestAdvice; +import datadog.trace.agent.tooling.Instrumenter; +import net.bytebuddy.agent.builder.AgentBuilder; + +@AutoService(Instrumenter.class) +public class NettyServerTestInstrumentation implements Instrumenter { + + @Override + public AgentBuilder instrument(final AgentBuilder agentBuilder) { + return agentBuilder + .type(named("io.netty.handler.codec.ByteToMessageDecoder")) + .transform( + new AgentBuilder.Transformer.ForAdvice() + .advice( + named("channelRead"), HttpServerTestAdvice.ServerEntryAdvice.class.getName())); + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayAsyncServerTest.groovy b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayAsyncServerTest.groovy new file mode 100644 index 0000000000..38953b437d --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayAsyncServerTest.groovy @@ -0,0 +1,46 @@ +package server + +class PlayAsyncServerTest { //extends PlayServerTest { +// @Override +// Server startServer(int port) { +// def router = +// new RoutingDsl() +// .GET(SUCCESS.getPath()).routeAsync({ +// CompletableFuture.supplyAsync({ +// controller(SUCCESS) { +// Results.status(SUCCESS.getStatus(), SUCCESS.getBody()) +// } +// }, HttpExecution.defaultContext()) +// } as Supplier) +// .GET(QUERY_PARAM.getPath()).routeAsync({ +// CompletableFuture.supplyAsync({ +// controller(QUERY_PARAM) { +// Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()) +// } +// }, HttpExecution.defaultContext()) +// } as Supplier) +// .GET(REDIRECT.getPath()).routeAsync({ +// CompletableFuture.supplyAsync({ +// controller(REDIRECT) { +// Results.found(REDIRECT.getBody()) +// } +// }, HttpExecution.defaultContext()) +// } as Supplier) +// .GET(ERROR.getPath()).routeAsync({ +// CompletableFuture.supplyAsync({ +// controller(ERROR) { +// Results.status(ERROR.getStatus(), ERROR.getBody()) +// } +// }, HttpExecution.defaultContext()) +// } as Supplier) +// .GET(EXCEPTION.getPath()).routeAsync({ +// CompletableFuture.supplyAsync({ +// controller(EXCEPTION) { +// throw new Exception(EXCEPTION.getBody()) +// } +// }, HttpExecution.defaultContext()) +// } as Supplier) +// +// return Server.forRouter(router.build(), port) +// } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayServerTest.groovy b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayServerTest.groovy new file mode 100644 index 0000000000..95fa6a0027 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/groovy/server/PlayServerTest.groovy @@ -0,0 +1,79 @@ +package server + +import datadog.opentracing.DDSpan +import datadog.trace.agent.test.asserts.TraceAssert +import datadog.trace.agent.test.base.HttpServerTest +import datadog.trace.api.DDSpanTypes +import datadog.trace.api.DDTags +import datadog.trace.bootstrap.instrumentation.api.Tags +import play.api.test.TestServer + +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.* + +class PlayServerTest extends HttpServerTest { + @Override + TestServer startServer(int port) { + def server = SyncServer.server(port) + server.start() + return server + } + + @Override + void stopServer(TestServer server) { + server.stop() + } + + @Override + String component() { + return "" + } + + @Override + String expectedOperationName() { + return "netty.request" + } + + @Override + boolean hasHandlerSpan() { + true + } + + @Override + // Return the handler span's name + String reorderHandlerSpan() { + "play.request" + } + + boolean testExceptionBody() { + // I can't figure out how to set a proper exception handler to customize the response body. + false + } + + @Override + void handlerSpan(TraceAssert trace, int index, Object parent, ServerEndpoint endpoint = SUCCESS) { + trace.span(index) { + serviceName expectedServiceName() + operationName "play.request" + spanType DDSpanTypes.HTTP_SERVER + errored endpoint == ERROR || endpoint == EXCEPTION + childOf(parent as DDSpan) + tags { + "$Tags.COMPONENT" "" + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER + "$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional + "$Tags.HTTP_URL" String + "$Tags.HTTP_METHOD" String + "$Tags.HTTP_STATUS" Integer + if (endpoint == ERROR) { + "$Tags.ERROR" true + } else if (endpoint == EXCEPTION) { + errorTags(Exception, EXCEPTION.body) + } + if (endpoint.query) { + "$DDTags.HTTP_QUERY" endpoint.query + } + defaultTags() + } + } + } +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/AsyncServer.scala b/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/AsyncServer.scala new file mode 100644 index 0000000000..228dcb95a3 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/AsyncServer.scala @@ -0,0 +1,5 @@ +package server + +object AsyncServer { + +} diff --git a/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/SyncServer.scala b/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/SyncServer.scala new file mode 100644 index 0000000000..1f36d66824 --- /dev/null +++ b/dd-java-agent/instrumentation/play-2.3/src/test/scala/server/SyncServer.scala @@ -0,0 +1,15 @@ +package server + +import datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint._ +import play.api.mvc.{Action, Handler, Results} +import play.api.test.{FakeApplication, TestServer} + +object SyncServer { + val routes: PartialFunction[(String, String), Handler] = { + case ("GET", "/success") => Action { request => Results.Status(SUCCESS.getStatus) } + } + + def server(port: Int): TestServer = { + TestServer(port, FakeApplication(withRoutes = routes)) + } +} diff --git a/settings.gradle b/settings.gradle index e184365078..9e75b55c12 100644 --- a/settings.gradle +++ b/settings.gradle @@ -116,6 +116,7 @@ include ':dd-java-agent:instrumentation:netty-3.8' include ':dd-java-agent:instrumentation:netty-4.0' include ':dd-java-agent:instrumentation:netty-4.1' include ':dd-java-agent:instrumentation:okhttp-3' +include ':dd-java-agent:instrumentation:play-2.3' include ':dd-java-agent:instrumentation:play-2.4' include ':dd-java-agent:instrumentation:play-2.6' include ':dd-java-agent:instrumentation:play-ws'