Migrate vertx tests to HttpServerTest
MODIFY
dd-java-agent/instrumentation/akka-http-10.0/src/test/groovy/AkkaHttpServerInstrumentationTest.groovy
dd-java-agent/instrumentation/akka-http-10.0/src/test/groovy/AkkaHttpServerInstrumentationTest.groovy
@@ -20,7 +20,7 @@ abstract class AkkaHttpServerInstrumentationTest extends HttpServerTest<AkkaHttp
}
@Override
- boolean hasExceptionBody() {
+ boolean testExceptionBody() {
false
}

MODIFY
dd-java-agent/instrumentation/netty-4.0/netty-4.0.gradle
dd-java-agent/instrumentation/netty-4.0/netty-4.0.gradle
@@ -19,6 +19,12 @@ muzzle {
versions = "[4.0.0.Final,4.1.0.Final)"
assertInverse = true
}
+ pass {
+ group = "io.vertx"
+ module = "vertx-core"
+ versions = "[2.0.0,3.3.0)"
+ assertInverse = true
+ }
}
apply plugin: 'org.unbroken-dome.test-sets'

MODIFY
dd-java-agent/instrumentation/netty-4.1/netty-4.1.gradle
dd-java-agent/instrumentation/netty-4.1/netty-4.1.gradle
@@ -18,6 +18,12 @@ muzzle {
versions = "[4.1.0.Final,)"
assertInverse = true
}
+ pass {
+ group = "io.vertx"
+ module = "vertx-core"
+ versions = "[3.3.0,)"
+ assertInverse = true
+ }
}
apply plugin: 'org.unbroken-dome.test-sets'

DELETE
dd-java-agent/instrumentation/vertx/src/test/groovy/VertxRxServerTest.groovy
-import datadog.trace.agent.test.AgentTestRunner
-import datadog.trace.agent.test.utils.OkHttpUtils
-import datadog.trace.agent.test.utils.PortUtils
-import datadog.trace.api.DDSpanTypes
-import io.netty.handler.codec.http.HttpResponseStatus
-import io.opentracing.tag.Tags
-import io.vertx.core.Vertx
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import spock.lang.Shared
-
-class VertxRxServerTest extends AgentTestRunner {
-
- @Shared
- OkHttpClient client = OkHttpUtils.client()
-
- @Shared
- int port
- @Shared
- Vertx server
-
- def setupSpec() {
- port = PortUtils.randomOpenPort()
- server = VertxRxWebTestServer.start(port)
- }
-
- def cleanupSpec() {
- server.close()
- }
-
- def "test server request/response"() {
- setup:
- def request = new Request.Builder()
- .url("http://localhost:$port/proxy")
- .header("x-datadog-trace-id", "123")
- .header("x-datadog-parent-id", "456")
- .get()
- .build()
- def response = client.newCall(request).execute()
-
- expect:
- response.code() == 200
- response.body().string() == "Hello World"
-
- and:
- assertTraces(2) {
- trace(0, 2) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName "GET /test"
- childOf(trace(1).get(1))
- spanType DDSpanTypes.HTTP_SERVER
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/test"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- defaultTags(true)
- }
- }
- span(1) {
- childOf span(0)
- assert span(1).operationName.endsWith('.tracedMethod')
- }
- }
- trace(1, 2) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName "GET /proxy"
- traceId "123"
- parentId "456"
- spanType DDSpanTypes.HTTP_SERVER
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/proxy"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- defaultTags(true)
- }
- }
- span(1) {
- serviceName "unnamed-java-app"
- operationName "netty.client.request"
- resourceName "GET /test"
- childOf(span(0))
- spanType DDSpanTypes.HTTP_CLIENT
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty-client"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/test"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
- defaultTags()
- }
- }
- }
- }
- }
-
- def "test #responseCode response handling"() {
- setup:
- def request = new Request.Builder().url("http://localhost:$port/$path").get().build()
- def response = client.newCall(request).execute()
-
- expect:
- response.code() == responseCode.code()
-
- and:
- assertTraces(1) {
- trace(0, 1) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName name
- spanType DDSpanTypes.HTTP_SERVER
- errored error
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" responseCode.code()
- "$Tags.HTTP_URL.key" "http://localhost:$port/$path"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- if (error) {
- tag("error", true)
- }
- defaultTags()
- }
- }
- }
- }
-
- where:
- responseCode | name | path | error
- HttpResponseStatus.OK | "GET /" | "" | false
- HttpResponseStatus.NOT_FOUND | "404" | "doesnt-exit" | false
- HttpResponseStatus.INTERNAL_SERVER_ERROR | "GET /error" | "error" | true
- }
-}

DELETE
dd-java-agent/instrumentation/vertx/src/test/groovy/VertxServerTest.groovy
-import datadog.trace.agent.test.AgentTestRunner
-import datadog.trace.agent.test.utils.OkHttpUtils
-import datadog.trace.agent.test.utils.PortUtils
-import datadog.trace.api.DDSpanTypes
-import io.netty.handler.codec.http.HttpResponseStatus
-import io.opentracing.tag.Tags
-import io.vertx.core.Vertx
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import spock.lang.Shared
-
-class VertxServerTest extends AgentTestRunner {
-
- @Shared
- OkHttpClient client = OkHttpUtils.client()
-
- @Shared
- int port
- @Shared
- Vertx server
-
- def setupSpec() {
- port = PortUtils.randomOpenPort()
- server = VertxWebTestServer.start(port)
- }
-
- def cleanupSpec() {
- server.close()
- }
-
- def "test server request/response"() {
- setup:
- def request = new Request.Builder()
- .url("http://localhost:$port/proxy")
- .header("x-datadog-trace-id", "123")
- .header("x-datadog-parent-id", "456")
- .get()
- .build()
- def response = client.newCall(request).execute()
-
- expect:
- response.code() == 200
- response.body().string() == "Hello World"
-
- and:
- assertTraces(2) {
- trace(0, 2) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName "GET /test"
- childOf(trace(1).get(1))
- spanType DDSpanTypes.HTTP_SERVER
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/test"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- defaultTags(true)
- }
- }
- span(1) {
- childOf span(0)
- assert span(1).operationName.endsWith('.tracedMethod')
- }
- }
- trace(1, 2) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName "GET /proxy"
- traceId "123"
- parentId "456"
- spanType DDSpanTypes.HTTP_SERVER
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/proxy"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- defaultTags(true)
- }
- }
- span(1) {
- serviceName "unnamed-java-app"
- operationName "netty.client.request"
- resourceName "GET /test"
- childOf(span(0))
- spanType DDSpanTypes.HTTP_CLIENT
- errored false
- tags {
- "$Tags.COMPONENT.key" "netty-client"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" 200
- "$Tags.HTTP_URL.key" "http://localhost:$port/test"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
- defaultTags()
- }
- }
- }
- }
- }
-
- def "test #responseCode response handling"() {
- setup:
- def request = new Request.Builder().url("http://localhost:$port/$path").get().build()
- def response = client.newCall(request).execute()
-
- expect:
- response.code() == responseCode.code()
-
- and:
- assertTraces(1) {
- trace(0, 1) {
- span(0) {
- serviceName "unnamed-java-app"
- operationName "netty.request"
- resourceName name
- spanType DDSpanTypes.HTTP_SERVER
- errored error
- tags {
- "$Tags.COMPONENT.key" "netty"
- "$Tags.HTTP_METHOD.key" "GET"
- "$Tags.HTTP_STATUS.key" responseCode.code()
- "$Tags.HTTP_URL.key" "http://localhost:$port/$path"
- "$Tags.PEER_HOSTNAME.key" "localhost"
- "$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
- "$Tags.PEER_PORT.key" Integer
- "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
- if (error) {
- tag("error", true)
- }
- defaultTags()
- }
- }
- }
- }
-
- where:
- responseCode | name | path | error
- HttpResponseStatus.OK | "GET /" | "" | false
- HttpResponseStatus.NOT_FOUND | "404" | "doesnt-exit" | false
- HttpResponseStatus.INTERNAL_SERVER_ERROR | "GET /error" | "error" | true
- }
-}

RENAME
dd-java-agent/instrumentation/vertx/src/test/groovy/VertxHttpClientTest.groovy
dd-java-agent/instrumentation/vertx/src/test/groovy/client/VertxHttpClientTest.groovy
+package client
+
import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
import io.vertx.core.Vertx

ADD
dd-java-agent/instrumentation/vertx/src/test/groovy/client/VertxRxCircuitBreakerWebClientTest.groovy
+package client
+
+import datadog.trace.agent.test.base.HttpClientTest
+import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
+import io.vertx.circuitbreaker.CircuitBreakerOptions
+import io.vertx.core.VertxOptions
+import io.vertx.core.http.HttpMethod
+import io.vertx.ext.web.client.HttpResponse
+import io.vertx.reactivex.circuitbreaker.CircuitBreaker
+import io.vertx.reactivex.core.Future
+import io.vertx.reactivex.core.Vertx
+import io.vertx.reactivex.ext.web.client.WebClient
+import spock.lang.Shared
+import spock.lang.Timeout
+
+import java.util.concurrent.CompletableFuture
+
+@Timeout(10)
+class VertxRxCircuitBreakerWebClientTest extends HttpClientTest<NettyHttpClientDecorator> {
+
+ @Shared
+ Vertx vertx = Vertx.vertx(new VertxOptions())
+ @Shared
+ WebClient client = WebClient.create(vertx)
+ @Shared
+ CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx,
+ new CircuitBreakerOptions()
+ .setTimeout(-1) // Disable the timeout otherwise it makes each test take this long.
+ )
+
+ @Override
+ int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
+ def request = client.request(HttpMethod.valueOf(method), uri.port, uri.host, "$uri")
+ headers.each { request.putHeader(it.key, it.value) }
+ Future<HttpResponse> result = breaker.execute { command ->
+ request.rxSend().doOnSuccess {
+ command.complete(it)
+ }.doOnError {
+ command.fail(it)
+ }.subscribe()
+ }
+
+ def future = new CompletableFuture<Integer>()
+ result.setHandler {
+ callback?.call()
+ if (it.succeeded()) {
+ future.complete(it.result().statusCode())
+ } else {
+ future.completeExceptionally(it.cause())
+ }
+ }
+ return future.get()
+ }
+
+ @Override
+ NettyHttpClientDecorator decorator() {
+ return NettyHttpClientDecorator.DECORATE
+ }
+
+ @Override
+ String expectedOperationName() {
+ return "netty.client.request"
+ }
+
+ @Override
+ boolean testRedirects() {
+ false
+ }
+
+ @Override
+ boolean testConnectionFailure() {
+ false
+ }
+}

RENAME
dd-java-agent/instrumentation/vertx/src/test/groovy/VertxRxWebClientTest.groovy
dd-java-agent/instrumentation/vertx/src/test/groovy/client/VertxRxWebClientTest.groovy
+package client
+
import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
import io.vertx.core.VertxOptions

ADD
dd-java-agent/instrumentation/vertx/src/test/groovy/server/NettyServerTestInstrumentation.java
+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()));
+ }
+}

ADD
dd-java-agent/instrumentation/vertx/src/test/groovy/server/VertxHttpServerTest.groovy
+package server
+
+import datadog.trace.agent.test.asserts.ListWriterAssert
+import datadog.trace.agent.test.base.HttpServerTest
+import datadog.trace.instrumentation.netty41.server.NettyHttpServerDecorator
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.SimpleType
+import io.vertx.core.AbstractVerticle
+import io.vertx.core.DeploymentOptions
+import io.vertx.core.Future
+import io.vertx.core.Vertx
+import io.vertx.core.VertxOptions
+import io.vertx.core.json.JsonObject
+import io.vertx.ext.web.Router
+import spock.lang.Shared
+
+import java.util.concurrent.CompletableFuture
+
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
+
+class VertxHttpServerTest extends HttpServerTest<NettyHttpServerDecorator> {
+ public static final String CONFIG_HTTP_SERVER_PORT = "http.server.port"
+
+ @Shared
+ Vertx server
+
+ @Override
+ void startServer(int port) {
+ server = Vertx.vertx(new VertxOptions()
+ // Useful for debugging:
+ // .setBlockedThreadCheckInterval(Integer.MAX_VALUE)
+ .setClusterPort(port))
+ final CompletableFuture<Void> future = new CompletableFuture<>()
+ server.deployVerticle(verticle().name,
+ new DeploymentOptions()
+ .setConfig(new JsonObject().put(CONFIG_HTTP_SERVER_PORT, port))
+ .setInstances(3)) { res ->
+ if (!res.succeeded()) {
+ throw new RuntimeException("Cannot deploy server Verticle", res.cause())
+ }
+ future.complete(null)
+ }
+
+ future.get()
+ }
+
+ protected Class<io.vertx.reactivex.core.AbstractVerticle> verticle() {
+ return VertxWebTestServer
+ }
+
+ @Override
+ void stopServer() {
+ server.close()
+ }
+
+ @Override
+ NettyHttpServerDecorator decorator() {
+ return NettyHttpServerDecorator.DECORATE
+ }
+
+ @Override
+ String expectedOperationName() {
+ "netty.request"
+ }
+
+ @Override
+ boolean testExceptionBody() {
+ false
+ }
+
+ static class VertxWebTestServer extends AbstractVerticle {
+
+ @Override
+ void start(final Future<Void> startFuture) {
+ final int port = config().getInteger(CONFIG_HTTP_SERVER_PORT)
+ final Router router = Router.router(vertx)
+
+ router.route(SUCCESS.path).handler { ctx ->
+ controller(SUCCESS) {
+ ctx.response().setStatusCode(SUCCESS.status).end(SUCCESS.body)
+ }
+ }
+ router.route(REDIRECT.path).handler { ctx ->
+ controller(REDIRECT) {
+ ctx.response().setStatusCode(REDIRECT.status).putHeader("location", REDIRECT.body)
+ }
+ }
+ router.route(ERROR.path).handler { ctx ->
+ controller(ERROR) {
+ ctx.response().setStatusCode(ERROR.status).end(ERROR.body)
+ }
+ }
+ router.route(EXCEPTION.path).handler { ctx ->
+ controller(EXCEPTION) {
+ throw new Exception(EXCEPTION.body)
+ }
+ }
+
+ vertx.createHttpServer()
+ .requestHandler { router.accept(it) }
+ .listen(port) { startFuture.complete() }
+ }
+ }
+
+ void cleanAndAssertTraces(
+ final int size,
+ @ClosureParams(value = SimpleType, options = "datadog.trace.agent.test.asserts.ListWriterAssert")
+ @DelegatesTo(value = ListWriterAssert, strategy = Closure.DELEGATE_FIRST)
+ final Closure spec) {
+ // If this is failing, make sure HttpServerTestAdvice is applied correctly.
+ TEST_WRITER.waitForTraces(size * 2)
+
+ // Netty closes the parent span before the controller returns, so we need to manually reorder it.
+ TEST_WRITER.each {
+ def controllerSpan = it.find {
+ it.operationName == "controller"
+ }
+ if (controllerSpan) {
+ it.remove(controllerSpan)
+ it.add(controllerSpan)
+ }
+ }
+ super.cleanAndAssertTraces(size, spec)
+ }
+}

ADD
dd-java-agent/instrumentation/vertx/src/test/groovy/server/VertxRxCircuitBreakerHttpServerTest.groovy
+package server
+
+import datadog.trace.agent.test.base.HttpServerTest
+import io.vertx.circuitbreaker.CircuitBreakerOptions
+import io.vertx.reactivex.circuitbreaker.CircuitBreaker
+import io.vertx.reactivex.core.AbstractVerticle
+import io.vertx.reactivex.core.Future
+import io.vertx.reactivex.ext.web.Router
+
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
+
+class VertxRxCircuitBreakerHttpServerTest extends VertxHttpServerTest {
+
+ @Override
+ protected Class<AbstractVerticle> verticle() {
+ return VertxRxCircuitBreakerWebTestServer
+ }
+
+ static class VertxRxCircuitBreakerWebTestServer extends AbstractVerticle {
+
+ @Override
+ void start(final io.vertx.core.Future<Void> startFuture) {
+ final int port = config().getInteger(CONFIG_HTTP_SERVER_PORT)
+ final Router router = Router.router(super.@vertx)
+ final CircuitBreaker breaker =
+ CircuitBreaker.create(
+ "my-circuit-breaker",
+ super.@vertx,
+ new CircuitBreakerOptions()
+ .setTimeout(-1) // Disable the timeout otherwise it makes each test take this long.
+ )
+
+ router.route(SUCCESS.path).handler { ctx ->
+ def result = breaker.execute { future ->
+ future.complete(SUCCESS)
+ }
+ result.setHandler {
+ if (it.failed()) {
+ throw it.cause();
+ }
+ HttpServerTest.ServerEndpoint endpoint = it.result()
+ controller(endpoint) {
+ ctx.response().setStatusCode(endpoint.status).end(endpoint.body)
+ }
+ }
+ }
+ router.route(REDIRECT.path).handler { ctx ->
+ def result = breaker.execute { future ->
+ future.complete(REDIRECT)
+ }
+ result.setHandler {
+ if (it.failed()) {
+ throw it.cause();
+ }
+ HttpServerTest.ServerEndpoint endpoint = it.result()
+ controller(endpoint) {
+ ctx.response().setStatusCode(endpoint.status).putHeader("location", endpoint.body)
+ }
+ }
+ }
+ router.route(ERROR.path).handler { ctx ->
+ def result = breaker.execute { future ->
+ future.complete(ERROR)
+ }
+ result.setHandler {
+ if (it.failed()) {
+ throw it.cause();
+ }
+ HttpServerTest.ServerEndpoint endpoint = it.result()
+ controller(endpoint) {
+ ctx.response().setStatusCode(endpoint.status).end(endpoint.body)
+ }
+ }
+ }
+ router.route(EXCEPTION.path).handler { ctx ->
+ def result = breaker.execute { future ->
+ future.fail(new Exception(EXCEPTION.body))
+ }
+ result.setHandler {
+ try {
+ def cause = it.cause()
+ controller(EXCEPTION) {
+ throw cause
+ }
+ } catch (Exception ex) {
+ ctx.response().setStatusCode(EXCEPTION.status).end(ex.message)
+ }
+ }
+ }
+
+ super.@vertx.createHttpServer()
+ .requestHandler { router.accept(it) }
+ .listen(port) { startFuture.complete() }
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/vertx/src/test/groovy/server/VertxRxHttpServerTest.groovy
+package server
+
+
+import io.vertx.core.Future
+import io.vertx.reactivex.core.AbstractVerticle
+import io.vertx.reactivex.ext.web.Router
+
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
+
+class VertxRxHttpServerTest extends VertxHttpServerTest {
+
+ @Override
+ protected Class<AbstractVerticle> verticle() {
+ return VertxRxWebTestServer
+ }
+
+ static class VertxRxWebTestServer extends AbstractVerticle {
+
+ @Override
+ void start(final Future<Void> startFuture) {
+ final int port = config().getInteger(CONFIG_HTTP_SERVER_PORT)
+ final Router router = Router.router(super.@vertx)
+
+ router.route(SUCCESS.path).handler { ctx ->
+ controller(SUCCESS) {
+ ctx.response().setStatusCode(SUCCESS.status).end(SUCCESS.body)
+ }
+ }
+ router.route(REDIRECT.path).handler { ctx ->
+ controller(REDIRECT) {
+ ctx.response().setStatusCode(REDIRECT.status).putHeader("location", REDIRECT.body)
+ }
+ }
+ router.route(ERROR.path).handler { ctx ->
+ controller(ERROR) {
+ ctx.response().setStatusCode(ERROR.status).end(ERROR.body)
+ }
+ }
+ router.route(EXCEPTION.path).handler { ctx ->
+ controller(EXCEPTION) {
+ throw new Exception(EXCEPTION.body)
+ }
+ }
+
+ super.@vertx.createHttpServer()
+ .requestHandler { router.accept(it) }
+ .listen(port) { startFuture.complete() }
+ }
+ }
+}

DELETE
dd-java-agent/instrumentation/vertx/src/test/java/VertxRxWebTestServer.java
-import datadog.trace.api.Trace;
-import io.vertx.circuitbreaker.CircuitBreakerOptions;
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.Future;
-import io.vertx.core.Vertx;
-import io.vertx.core.VertxOptions;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
-import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.buffer.Buffer;
-import io.vertx.reactivex.ext.web.Router;
-import io.vertx.reactivex.ext.web.RoutingContext;
-import io.vertx.reactivex.ext.web.client.WebClient;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class VertxRxWebTestServer extends AbstractVerticle {
- public static final String CONFIG_HTTP_SERVER_PORT = "http.server.port";
-
- public static Vertx start(final int port) throws ExecutionException, InterruptedException {
- /* This is highly against Vertx ideas, but our tests are synchronous
- so we have to make sure server is up and running */
- final CompletableFuture<Void> future = new CompletableFuture<>();
-
- final Vertx vertx = Vertx.vertx(new VertxOptions().setClusterPort(port));
-
- vertx.deployVerticle(
- VertxRxWebTestServer.class.getName(),
- new DeploymentOptions()
- .setConfig(new JsonObject().put(CONFIG_HTTP_SERVER_PORT, port))
- .setInstances(3),
- res -> {
- if (!res.succeeded()) {
- throw new RuntimeException("Cannot deploy server Verticle", res.cause());
- }
- future.complete(null);
- });
-
- future.get();
-
- return vertx;
- }
-
- @Override
- public void start(final Future<Void> startFuture) {
- // final io.vertx.reactivex.core.Vertx vertx = new io.vertx.reactivex.core.Vertx(this.vertx);
- final WebClient client = WebClient.create(vertx);
-
- final int port = config().getInteger(CONFIG_HTTP_SERVER_PORT);
-
- final Router router = Router.router(vertx);
- final CircuitBreaker breaker =
- CircuitBreaker.create(
- "my-circuit-breaker",
- vertx,
- new CircuitBreakerOptions()
- .setMaxFailures(5) // number of failure before opening the circuit
- .setTimeout(2000) // consider a failure if the operation does not succeed in time
- // .setFallbackOnFailure(true) // do we call the fallback on failure
- .setResetTimeout(10000) // time spent in open state before attempting to re-try
- );
-
- router
- .route("/")
- .handler(
- routingContext -> {
- routingContext.response().putHeader("content-type", "text/html").end("Hello World");
- });
- router
- .route("/error")
- .handler(
- routingContext -> {
- routingContext.response().setStatusCode(500).end();
- });
- router
- .route("/proxy")
- .handler(
- routingContext -> {
- breaker.execute(
- ctx -> {
- client
- .get(port, "localhost", "/test")
- .rxSendBuffer(
- Optional.ofNullable(routingContext.getBody()).orElse(Buffer.buffer()))
- .subscribe(
- response -> {
- routingContext
- .response()
- .setStatusCode(response.statusCode())
- .end(response.body());
- });
- });
- });
- router
- .route("/test")
- .handler(
- routingContext -> {
- tracedMethod();
- routingContext.next();
- })
- .blockingHandler(RoutingContext::next)
- .handler(
- routingContext -> {
- routingContext.response().putHeader("content-type", "text/html").end("Hello World");
- });
-
- vertx
- .createHttpServer()
- .requestHandler(router::accept)
- .listen(port, h -> startFuture.complete());
- }
-
- @Trace
- private void tracedMethod() {}
-}

DELETE
dd-java-agent/instrumentation/vertx/src/test/java/VertxWebTestServer.java
-import static datadog.trace.agent.test.AgentTestRunner.blockUntilChildSpansFinished;
-
-import datadog.trace.api.Trace;
-import io.vertx.core.AbstractVerticle;
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.Future;
-import io.vertx.core.Vertx;
-import io.vertx.core.VertxOptions;
-import io.vertx.core.buffer.Buffer;
-import io.vertx.core.http.HttpClient;
-import io.vertx.core.json.JsonObject;
-import io.vertx.ext.web.Router;
-import io.vertx.ext.web.RoutingContext;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class VertxWebTestServer extends AbstractVerticle {
- public static final String CONFIG_HTTP_SERVER_PORT = "http.server.port";
-
- public static Vertx start(final int port) throws ExecutionException, InterruptedException {
- /* This is highly against Vertx ideas, but our tests are synchronous
- so we have to make sure server is up and running */
- final CompletableFuture<Void> future = new CompletableFuture<>();
-
- final Vertx vertx = Vertx.vertx(new VertxOptions().setClusterPort(port));
-
- vertx.deployVerticle(
- VertxWebTestServer.class.getName(),
- new DeploymentOptions()
- .setConfig(new JsonObject().put(CONFIG_HTTP_SERVER_PORT, port))
- .setInstances(3),
- res -> {
- if (!res.succeeded()) {
- throw new RuntimeException("Cannot deploy server Verticle", res.cause());
- }
- future.complete(null);
- });
-
- future.get();
-
- return vertx;
- }
-
- @Override
- public void start(final Future<Void> startFuture) {
- final HttpClient client = vertx.createHttpClient();
-
- final int port = config().getInteger(CONFIG_HTTP_SERVER_PORT);
-
- final Router router = Router.router(vertx);
-
- router
- .route("/")
- .handler(
- routingContext -> {
- routingContext.response().putHeader("content-type", "text/html").end("Hello World");
- });
- router
- .route("/error")
- .handler(
- routingContext -> {
- routingContext.response().setStatusCode(500).end();
- });
- router
- .route("/proxy")
- .handler(
- routingContext -> {
- client
- .get(
- port,
- "localhost",
- "/test",
- response -> {
- response.bodyHandler(
- buffer -> {
- routingContext
- .response()
- .setStatusCode(response.statusCode())
- .end(buffer);
- });
- blockUntilChildSpansFinished(1);
- })
- .end(Optional.ofNullable(routingContext.getBody()).orElse(Buffer.buffer()));
- });
- router
- .route("/test")
- .handler(
- routingContext -> {
- tracedMethod();
- routingContext.next();
- })
- .blockingHandler(RoutingContext::next)
- .handler(
- routingContext -> {
- routingContext.response().putHeader("content-type", "text/html").end("Hello World");
- });
-
- vertx
- .createHttpServer()
- .requestHandler(router::accept)
- .listen(port, h -> startFuture.complete());
- }
-
- @Trace
- private void tracedMethod() {}
-}

MODIFY
dd-java-agent/instrumentation/vertx/vertx.gradle
dd-java-agent/instrumentation/vertx/vertx.gradle
@@ -5,21 +5,6 @@ ext {
apply from: "${rootDir}/gradle/java.gradle"
-muzzle {
- pass {
- group = "io.vertx"
- module = "vertx-web"
- versions = "[4.1.0.Final,)"
- assertInverse = true
- }
- pass {
- group = "io.netty"
- module = "netty"
- versions = "[4.1.0.Final,)"
- assertInverse = true
- }
-}
-
apply plugin: 'org.unbroken-dome.test-sets'
testSets {

MODIFY
dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy
dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy
@@ -72,15 +72,15 @@ abstract class HttpServerTest<DECORATOR extends HttpServerDecorator> extends Age
true
}
- boolean hasExceptionBody() {
+ boolean testExceptionBody() {
true
}
public enum ServerEndpoint {
SUCCESS("success", 200, "success"),
+ REDIRECT("redirect", 302, null),
ERROR("error", 500, "controller error"),
EXCEPTION("exception", 500, "controller exception"),
- REDIRECT("redirect", 302, null),
NOT_FOUND("notFound", 404, "not found"),
AUTH_REQUIRED("authRequired", 200, null),
@@ -214,7 +214,7 @@ abstract class HttpServerTest<DECORATOR extends HttpServerDecorator> extends Age
expect:
response.code() == EXCEPTION.status
- if (hasExceptionBody()) {
+ if (testExceptionBody()) {
assert response.body().string() == EXCEPTION.body
}

Migrate vertx tests to HttpServerTest