diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/client/PlayWsClientTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/client/PlayWsClientTest.groovy deleted file mode 100644 index 1cfe325aca58..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/client/PlayWsClientTest.groovy +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package client - -import io.opentelemetry.api.common.AttributeKey -import io.opentelemetry.instrumentation.test.AgentTestTrait -import io.opentelemetry.instrumentation.test.base.HttpClientTest -import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult -import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection -import io.opentelemetry.semconv.NetworkAttributes -import play.libs.ws.WS -import play.libs.ws.WSRequest -import play.libs.ws.WSResponse -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Subject - -import java.util.concurrent.CompletableFuture -import java.util.concurrent.CompletionStage - -class PlayWsClientTest extends HttpClientTest implements AgentTestTrait { - @Subject - @Shared - @AutoCleanup - def client = WS.newClient(-1) - - @Override - WSRequest buildRequest(String method, URI uri, Map headers) { - def request = client.url(uri.toString()) - headers.entrySet().each { - request.setHeader(it.key, it.value) - } - return request - } - - @Override - int sendRequest(WSRequest request, String method, URI uri, Map headers) { - return internalSendRequest(request, method).toCompletableFuture().get().status - } - - @Override - void sendRequestWithCallback(WSRequest request, String method, URI uri, Map headers, HttpClientResult requestResult) { - internalSendRequest(request, method).whenComplete { response, throwable -> - requestResult.complete({ response.status }, throwable) - } - } - - private static CompletionStage internalSendRequest(WSRequest request, String method) { - def result = new CompletableFuture() - def promise = request.execute(method) - promise.onRedeem({ response -> - result.complete(response) - }) - promise.onFailure({ throwable -> - result.completeExceptionally(throwable) - }) - return result - } - - //TODO see https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/2347 -// @Override -// String userAgent() { -// return "AHC" -// } - - @Override - boolean testRedirects() { - false - } - - @Override - boolean testReadTimeout() { - return false - } - - @Override - Set> httpAttributes(URI uri) { - def attributes = super.httpAttributes(uri) - attributes.remove(NetworkAttributes.NETWORK_PROTOCOL_VERSION) - attributes - } - - @Override - SingleConnection createSingleConnection(String host, int port) { - // Play HTTP client uses AsyncHttpClient internally which does not support HTTP 1.1 pipelining - // nor waiting for connection pool slots to free up. Therefore making a single connection test - // would require manually sequencing the connections, which is not meaningful for a high - // concurrency test. - return null - } -} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayAsyncServerTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayAsyncServerTest.groovy deleted file mode 100644 index 13bbc76772a9..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayAsyncServerTest.groovy +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package server - -import play.libs.F.Function0 -import play.mvc.Results -import play.routing.RoutingDsl -import play.server.Server - -import scala.Tuple2 -import scala.collection.JavaConverters - -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS -import static play.libs.F.Promise.promise -import static play.mvc.Http.Context.Implicit.request - -class PlayAsyncServerTest extends PlayServerTest { - @Override - Server startServer(int port) { - def router = - new RoutingDsl() - .GET(SUCCESS.getPath()).routeAsync({ - promise({ - controller(SUCCESS) { - Results.status(SUCCESS.getStatus(), SUCCESS.getBody()) - } - }) - } as Function0) - .GET(INDEXED_CHILD.getPath()).routeTo({ - promise({ - controller(INDEXED_CHILD) { - INDEXED_CHILD.collectSpanAttributes { request().getQueryString(it) } - Results.status(INDEXED_CHILD.getStatus()) - } - }) - } as Function0) - .GET(QUERY_PARAM.getPath()).routeAsync({ - promise({ - controller(QUERY_PARAM) { - Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()) - } - }) - } as Function0) - .GET(REDIRECT.getPath()).routeAsync({ - promise({ - controller(REDIRECT) { - Results.found(REDIRECT.getBody()) - } - }) - } as Function0) - .GET(CAPTURE_HEADERS.getPath()).routeAsync({ - promise({ - controller(CAPTURE_HEADERS) { - def javaResult = Results.status(CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) - def headers = Arrays.asList(new Tuple2<>("X-Test-Response", request().getHeader("X-Test-Request"))) - def scalaResult = javaResult.toScala().withHeaders(JavaConverters.asScalaIteratorConverter(headers.iterator()).asScala().toSeq()) - - return new Results.Status(scalaResult) - } - }) - } as Function0) - .GET(ERROR.getPath()).routeAsync({ - promise({ - controller(ERROR) { - Results.status(ERROR.getStatus(), ERROR.getBody()) - } - }) - } as Function0) - .GET(EXCEPTION.getPath()).routeAsync({ - promise({ - controller(EXCEPTION) { - throw new Exception(EXCEPTION.getBody()) - } - }) - } as Function0) - - return Server.forRouter(router.build(), port) - } -} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayServerTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayServerTest.groovy deleted file mode 100644 index 69383be02d11..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/groovy/server/PlayServerTest.groovy +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package server - -import io.opentelemetry.api.common.AttributeKey -import io.opentelemetry.api.trace.StatusCode -import io.opentelemetry.instrumentation.test.AgentTestTrait -import io.opentelemetry.instrumentation.test.asserts.TraceAssert -import io.opentelemetry.instrumentation.test.base.HttpServerTest -import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint -import io.opentelemetry.sdk.trace.data.SpanData -import io.opentelemetry.semconv.HttpAttributes -import play.libs.F.Function0 -import play.mvc.Results -import play.routing.RoutingDsl -import play.server.Server - -import scala.Tuple2 -import scala.collection.JavaConverters - -import static io.opentelemetry.api.trace.SpanKind.INTERNAL -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS -import static play.mvc.Http.Context.Implicit.request - -class PlayServerTest extends HttpServerTest implements AgentTestTrait { - @Override - Server startServer(int port) { - def router = - new RoutingDsl() - .GET(SUCCESS.getPath()).routeTo({ - controller(SUCCESS) { - Results.status(SUCCESS.getStatus(), SUCCESS.getBody()) - } - } as Function0) - .GET(INDEXED_CHILD.getPath()).routeTo({ - controller(INDEXED_CHILD) { - INDEXED_CHILD.collectSpanAttributes { request().getQueryString(it) } - Results.status(INDEXED_CHILD.getStatus()) - } - } as Function0) - .GET(QUERY_PARAM.getPath()).routeTo({ - controller(QUERY_PARAM) { - Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()) - } - } as Function0) - .GET(REDIRECT.getPath()).routeTo({ - controller(REDIRECT) { - Results.found(REDIRECT.getBody()) - } - } as play.libs.F.Function0) - .GET(CAPTURE_HEADERS.getPath()).routeTo({ - controller(CAPTURE_HEADERS) { - def javaResult = Results.status(CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) - def headers = Arrays.asList(new Tuple2<>("X-Test-Response", request().getHeader("X-Test-Request"))) - def scalaResult = javaResult.toScala().withHeaders(JavaConverters.asScalaIteratorConverter(headers.iterator()).asScala().toSeq()) - - return new Results.Status(scalaResult) - } - } as Function0) - .GET(ERROR.getPath()).routeTo({ - controller(ERROR) { - Results.status(ERROR.getStatus(), ERROR.getBody()) - } - } as Function0) - .GET(EXCEPTION.getPath()).routeTo({ - controller(EXCEPTION) { - throw new Exception(EXCEPTION.getBody()) - } - } as Function0) - - return Server.forRouter(router.build(), port) - } - - @Override - void stopServer(Server server) { - server.stop() - } - - @Override - boolean hasHandlerSpan(ServerEndpoint endpoint) { - true - } - - @Override - boolean testHttpPipelining() { - false - } - - @Override - boolean verifyServerSpanEndTime() { - // server spans are ended inside of the controller spans - return false - } - - @Override - void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint = SUCCESS) { - trace.span(index) { - name "play.request" - kind INTERNAL - if (endpoint == EXCEPTION) { - status StatusCode.ERROR - errorEvent(Exception, EXCEPTION.body) - } - childOf((SpanData) parent) - } - } - - @Override - Set> httpAttributes(ServerEndpoint endpoint) { - def attributes = super.httpAttributes(endpoint) - attributes.remove(HttpAttributes.HTTP_ROUTE) - attributes - } - - @Override - int getResponseCodeOnNonStandardHttpMethod() { - 404 - } -} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java new file mode 100644 index 000000000000..191603bb435f --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java @@ -0,0 +1,112 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.client; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions; +import io.opentelemetry.semconv.NetworkAttributes; +import java.net.URI; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import play.libs.F; +import play.libs.ws.WS; +import play.libs.ws.WSClient; +import play.libs.ws.WSRequest; +import play.libs.ws.WSResponse; + +class PlayWsClientTest extends AbstractHttpClientTest { + + @RegisterExtension + static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent(); + + static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + + private static WSClient wsClient; + + @BeforeEach + void setUp() { + wsClient = WS.newClient(-1); + autoCleanup.deferCleanup(wsClient); + } + + @Override + public WSRequest buildRequest(String method, URI uri, Map headers) { + WSRequest request = wsClient.url(uri.toString()); + headers.forEach(request::setHeader); + return request; + } + + @Override + public int sendRequest(WSRequest wsRequest, String method, URI uri, Map headers) + throws ExecutionException, InterruptedException { + return internalSendRequest(wsRequest, method).toCompletableFuture().get().getStatus(); + } + + @Override + public void sendRequestWithCallback( + WSRequest wsRequest, + String method, + URI uri, + Map headers, + HttpClientResult httpClientResult) { + internalSendRequest(wsRequest, method) + .whenComplete( + (wsResponse, throwable) -> { + if (wsResponse != null) { + httpClientResult.complete(wsResponse::getStatus, throwable); + } else { + httpClientResult.complete( + () -> { + throw new IllegalArgumentException("wsResponse is null!", throwable); + }, + throwable); + } + }); + } + + @Override + protected void configure(HttpClientTestOptions.Builder optionsBuilder) { + optionsBuilder.setTestRedirects(false); + optionsBuilder.setTestReadTimeout(false); + optionsBuilder.setHttpAttributes( + uri -> { + Set> attributes = + new HashSet<>(HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES); + attributes.remove(NetworkAttributes.NETWORK_PROTOCOL_VERSION); + return attributes; + }); + + optionsBuilder.spanEndsAfterBody(); + + // Play HTTP client uses AsyncHttpClient internally which does not support HTTP 1.1 pipelining + // nor waiting for connection pool slots to free up. Therefore making a single connection test + // would require manually sequencing the connections, which is not meaningful for a high + // concurrency test. + optionsBuilder.setSingleConnectionFactory( + (a, b) -> + null); // this can be omitted as it's the default. it's here for the comment above. + } + + private static CompletionStage internalSendRequest( + WSRequest wsRequest, String method) { + CompletableFuture result = new CompletableFuture<>(); + F.Promise promise = wsRequest.execute(method); + promise.onRedeem(result::complete); + promise.onFailure(result::completeExceptionally); + return result; + } +} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java new file mode 100644 index 000000000000..f0fd0e762e5f --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java @@ -0,0 +1,112 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.server; + +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS; + +import java.util.Collections; +import play.libs.F; +import play.mvc.Results; +import play.routing.RoutingDsl; +import play.server.Server; +import scala.Tuple2; +import scala.collection.JavaConverters; + +class PlayAsyncServerTest extends PlayServerTest { + + @Override + protected Server setupServer() { + RoutingDsl router = + new RoutingDsl() + .GET(SUCCESS.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + SUCCESS, + () -> Results.status(SUCCESS.getStatus(), SUCCESS.getBody())))) + .GET(INDEXED_CHILD.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + INDEXED_CHILD, + () -> { + INDEXED_CHILD.collectSpanAttributes( + it -> + play.mvc.Http.Context.Implicit.request() + .getQueryString(it)); + return Results.status(INDEXED_CHILD.getStatus()); + }))) + .GET(QUERY_PARAM.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + QUERY_PARAM, + () -> + Results.status( + QUERY_PARAM.getStatus(), QUERY_PARAM.getBody())))) + .GET(REDIRECT.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> controller(REDIRECT, () -> Results.found(REDIRECT.getBody())))) + .GET(CAPTURE_HEADERS.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + CAPTURE_HEADERS, + () -> { + Results.Status javaResult = + Results.status( + CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()); + Tuple2 header = + new Tuple2<>( + "X-Test-Response", + play.mvc.Http.Context.Implicit.request() + .getHeader("X-Test-Request")); + return new Results.Status( + javaResult + .toScala() + .withHeaders( + JavaConverters.asScalaIteratorConverter( + Collections.singletonList(header).iterator()) + .asScala() + .toSeq())); + }))) + .GET(ERROR.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + ERROR, () -> Results.status(ERROR.getStatus(), ERROR.getBody())))) + .GET(EXCEPTION.getPath()) + .routeAsync( + () -> + F.Promise.promise( + () -> + controller( + EXCEPTION, + () -> { + throw new IllegalArgumentException(EXCEPTION.getBody()); + }))); + + return Server.forRouter(router.build(), port); + } +} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java new file mode 100644 index 000000000000..48a7459c12c2 --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/play24Test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java @@ -0,0 +1,139 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.server; + +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions; +import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.HttpAttributes; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.junit.jupiter.api.extension.RegisterExtension; +import play.mvc.Results; +import play.routing.RoutingDsl; +import play.server.Server; +import scala.Tuple2; +import scala.collection.JavaConverters; + +class PlayServerTest extends AbstractHttpServerTest { + + @RegisterExtension + static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent(); + + @Override + protected Server setupServer() { + RoutingDsl router = + new RoutingDsl() + .GET(SUCCESS.getPath()) + .routeTo( + () -> + controller( + SUCCESS, () -> Results.status(SUCCESS.getStatus(), SUCCESS.getBody()))) + .GET(INDEXED_CHILD.getPath()) + .routeTo( + () -> + controller( + INDEXED_CHILD, + () -> { + INDEXED_CHILD.collectSpanAttributes( + it -> play.mvc.Http.Context.Implicit.request().getQueryString(it)); + return Results.status(INDEXED_CHILD.getStatus()); + })) + .GET(QUERY_PARAM.getPath()) + .routeTo( + () -> + controller( + QUERY_PARAM, + () -> Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()))) + .GET(REDIRECT.getPath()) + .routeTo(() -> controller(REDIRECT, () -> Results.found(REDIRECT.getBody()))) + .GET(CAPTURE_HEADERS.getPath()) + .routeTo( + () -> + controller( + CAPTURE_HEADERS, + () -> { + Results.Status javaResult = + Results.status( + CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()); + Tuple2 header = + new Tuple2<>( + "X-Test-Response", + play.mvc.Http.Context.Implicit.request() + .getHeader("X-Test-Request")); + return new Results.Status( + javaResult + .toScala() + .withHeaders( + JavaConverters.asScalaIteratorConverter( + Collections.singletonList(header).iterator()) + .asScala() + .toSeq())); + })) + .GET(ERROR.getPath()) + .routeTo( + () -> controller(ERROR, () -> Results.status(ERROR.getStatus(), ERROR.getBody()))) + .GET(EXCEPTION.getPath()) + .routeTo( + () -> + controller( + EXCEPTION, + () -> { + throw new IllegalArgumentException(EXCEPTION.getBody()); + })); + + return Server.forRouter(router.build(), port); + } + + @Override + protected void stopServer(Server server) { + server.stop(); + } + + @Override + protected void configure(HttpServerTestOptions options) { + options.setHasHandlerSpan(unused -> true); + options.setTestHttpPipelining(false); + options.setResponseCodeOnNonStandardHttpMethod(404); + options.setVerifyServerSpanEndTime( + false); // server spans are ended inside of the controller spans + options.setHttpAttributes( + serverEndpoint -> { + Set> attributes = + new HashSet<>(HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES); + attributes.remove(HttpAttributes.HTTP_ROUTE); + return attributes; + }); + + options.setExpectedException(new IllegalArgumentException(EXCEPTION.getBody())); + } + + @Override + public SpanDataAssert assertHandlerSpan( + SpanDataAssert span, String method, ServerEndpoint endpoint) { + span.hasName("play.request").hasKind(INTERNAL); + if (endpoint == EXCEPTION) { + span.hasStatus(StatusData.error()); + span.hasException(new IllegalArgumentException(EXCEPTION.getBody())); + } + return span; + } +} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/client/PlayWsClientTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/client/PlayWsClientTest.groovy deleted file mode 100644 index 4d10e1ed4fbc..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/client/PlayWsClientTest.groovy +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package client - - -import io.opentelemetry.instrumentation.test.AgentTestTrait -import io.opentelemetry.instrumentation.test.base.HttpClientTest -import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult -import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection -import play.libs.ws.WS -import play.libs.ws.WSRequest -import play.libs.ws.WSResponse -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Subject - -import java.util.concurrent.CompletionStage - -// 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 implements AgentTestTrait { - @Subject - @Shared - @AutoCleanup - def client = WS.newClient(-1) - - @Override - WSRequest buildRequest(String method, URI uri, Map headers) { - def request = client.url(uri.toString()) - headers.entrySet().each { - request.setHeader(it.key, it.value) - } - return request - } - - @Override - int sendRequest(WSRequest request, String method, URI uri, Map headers) { - return internalSendRequest(request, method).toCompletableFuture().get().status - } - - @Override - void sendRequestWithCallback(WSRequest request, String method, URI uri, Map headers, HttpClientResult requestResult) { - internalSendRequest(request, method).whenComplete { response, throwable -> - requestResult.complete({ response.status }, throwable) - } - } - - private static CompletionStage internalSendRequest(WSRequest request, String method) { - return request.execute(method) - } - - @Override - boolean testRedirects() { - false - } - - @Override - boolean testReadTimeout() { - return false - } - - @Override - SingleConnection createSingleConnection(String host, int port) { - // Play HTTP client uses AsyncHttpClient internally which does not support HTTP 1.1 pipelining - // nor waiting for connection pool slots to free up. Therefore making a single connection test - // would require manually sequencing the connections, which is not meaningful for a high - // concurrency test. - return null - } -} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayAsyncServerTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayAsyncServerTest.groovy deleted file mode 100644 index de342030bba2..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayAsyncServerTest.groovy +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package server - -import play.libs.concurrent.HttpExecution -import play.mvc.Results -import play.routing.RoutingDsl -import play.server.Server - -import java.util.concurrent.CompletableFuture -import java.util.function.Supplier - -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS -import static play.mvc.Http.Context.Implicit.request - -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(INDEXED_CHILD.getPath()).routeTo({ - CompletableFuture.supplyAsync({ - controller(INDEXED_CHILD) { - INDEXED_CHILD.collectSpanAttributes { request().getQueryString(it) } - Results.status(INDEXED_CHILD.getStatus()) - } - }, 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(CAPTURE_HEADERS.getPath()).routeAsync({ - CompletableFuture.supplyAsync({ - controller(CAPTURE_HEADERS) { - Results.status(CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) - .withHeader("X-Test-Response", request().getHeader("X-Test-Request")) - } - }, 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/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayServerTest.groovy b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayServerTest.groovy deleted file mode 100644 index 101890bd7068..000000000000 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/groovy/server/PlayServerTest.groovy +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package server - -import io.opentelemetry.api.common.AttributeKey -import io.opentelemetry.api.trace.StatusCode -import io.opentelemetry.instrumentation.test.AgentTestTrait -import io.opentelemetry.instrumentation.test.asserts.TraceAssert -import io.opentelemetry.instrumentation.test.base.HttpServerTest -import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint -import io.opentelemetry.sdk.trace.data.SpanData -import io.opentelemetry.semconv.HttpAttributes -import play.mvc.Results -import play.routing.RoutingDsl -import play.server.Server - -import java.util.function.Supplier - -import static io.opentelemetry.api.trace.SpanKind.INTERNAL -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT -import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS -import static play.mvc.Http.Context.Implicit.request - -class PlayServerTest extends HttpServerTest implements AgentTestTrait { - @Override - Server startServer(int port) { - def router = - new RoutingDsl() - .GET(SUCCESS.getPath()).routeTo({ - controller(SUCCESS) { - Results.status(SUCCESS.getStatus(), SUCCESS.getBody()) - } - } as Supplier) - .GET(INDEXED_CHILD.getPath()).routeTo({ - controller(INDEXED_CHILD) { - INDEXED_CHILD.collectSpanAttributes { request().getQueryString(it) } - Results.status(INDEXED_CHILD.getStatus()) - } - } as Supplier) - .GET(QUERY_PARAM.getPath()).routeTo({ - controller(QUERY_PARAM) { - Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()) - } - } as Supplier) - .GET(REDIRECT.getPath()).routeTo({ - controller(REDIRECT) { - Results.found(REDIRECT.getBody()) - } - } as Supplier) - .GET(CAPTURE_HEADERS.getPath()).routeTo({ - controller(CAPTURE_HEADERS) { - Results.status(CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) - .withHeader("X-Test-Response", request().getHeader("X-Test-Request")) - } - } as Supplier) - .GET(ERROR.getPath()).routeTo({ - controller(ERROR) { - Results.status(ERROR.getStatus(), ERROR.getBody()) - } - } as Supplier) - .GET(EXCEPTION.getPath()).routeTo({ - controller(EXCEPTION) { - throw new Exception(EXCEPTION.getBody()) - } - } as Supplier) - - return Server.forRouter(router.build(), port) - } - - @Override - void stopServer(Server server) { - server.stop() - } - - @Override - boolean hasHandlerSpan(ServerEndpoint endpoint) { - true - } - - @Override - boolean testHttpPipelining() { - false - } - - @Override - boolean verifyServerSpanEndTime() { - // server spans are ended inside of the controller spans - return false - } - - @Override - void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint = SUCCESS) { - trace.span(index) { - name "play.request" - kind INTERNAL - if (endpoint == EXCEPTION) { - status StatusCode.ERROR - errorEvent(Exception, EXCEPTION.body) - } - childOf((SpanData) parent) - } - } - - @Override - Set> httpAttributes(ServerEndpoint endpoint) { - def attributes = super.httpAttributes(endpoint) - attributes.remove(HttpAttributes.HTTP_ROUTE) - attributes - } - - @Override - int getResponseCodeOnNonStandardHttpMethod() { - 404 - } -} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java new file mode 100644 index 000000000000..78003c33c7bf --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/client/PlayWsClientTest.java @@ -0,0 +1,96 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.client; + +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import play.libs.ws.WS; +import play.libs.ws.WSClient; +import play.libs.ws.WSRequest; +import play.libs.ws.WSResponse; + +// 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 AbstractHttpClientTest { + + @RegisterExtension + static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent(); + + static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + + private static WSClient wsClient; + + @BeforeEach + void setUp() { + wsClient = WS.newClient(-1); + autoCleanup.deferCleanup(wsClient); + } + + @Override + public WSRequest buildRequest(String method, URI uri, Map headers) { + WSRequest request = wsClient.url(uri.toString()); + headers.forEach(request::setHeader); + return request; + } + + @Override + public int sendRequest(WSRequest wsRequest, String method, URI uri, Map headers) + throws ExecutionException, InterruptedException { + return internalSendRequest(wsRequest, method).toCompletableFuture().get().getStatus(); + } + + @Override + public void sendRequestWithCallback( + WSRequest wsRequest, + String method, + URI uri, + Map headers, + HttpClientResult httpClientResult) { + internalSendRequest(wsRequest, method) + .whenComplete( + (wsResponse, throwable) -> { + if (wsResponse != null) { + httpClientResult.complete(wsResponse::getStatus, throwable); + } else { + httpClientResult.complete( + () -> { + throw new IllegalArgumentException("wsResponse is null!", throwable); + }, + throwable); + } + }); + } + + @Override + protected void configure(HttpClientTestOptions.Builder optionsBuilder) { + optionsBuilder.setTestRedirects(false); + optionsBuilder.setTestReadTimeout(false); + optionsBuilder.spanEndsAfterBody(); + + // Play HTTP client uses AsyncHttpClient internally which does not support HTTP 1.1 pipelining + // nor waiting for connection pool slots to free up. Therefore making a single connection test + // would require manually sequencing the connections, which is not meaningful for a high + // concurrency test. + optionsBuilder.setSingleConnectionFactory( + (a, b) -> + null); // this can be omitted as it's the default. it's here for the comment above. + } + + private static CompletionStage internalSendRequest( + WSRequest wsRequest, String method) { + return wsRequest.execute(method); + } +} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java new file mode 100644 index 000000000000..bc7a29a67e31 --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayAsyncServerTest.java @@ -0,0 +1,112 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.server; + +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS; + +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension; +import java.util.concurrent.CompletableFuture; +import org.junit.jupiter.api.extension.RegisterExtension; +import play.libs.concurrent.HttpExecution; +import play.mvc.Results; +import play.routing.RoutingDsl; +import play.server.Server; + +class PlayAsyncServerTest extends PlayServerTest { + + @RegisterExtension + static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent(); + + @Override + protected Server setupServer() { + RoutingDsl router = + new RoutingDsl() + .GET(SUCCESS.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + SUCCESS, + () -> Results.status(SUCCESS.getStatus(), SUCCESS.getBody())), + HttpExecution.defaultContext())) + .GET(INDEXED_CHILD.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + INDEXED_CHILD, + () -> { + INDEXED_CHILD.collectSpanAttributes( + it -> + play.mvc.Http.Context.Implicit.request() + .getQueryString(it)); + return Results.status( + INDEXED_CHILD.getStatus(), INDEXED_CHILD.getBody()); + }), + HttpExecution.defaultContext())) + .GET(QUERY_PARAM.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + QUERY_PARAM, + () -> + Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody())), + HttpExecution.defaultContext())) + .GET(REDIRECT.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> controller(REDIRECT, () -> Results.found(REDIRECT.getBody())), + HttpExecution.defaultContext())) + .GET(CAPTURE_HEADERS.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + CAPTURE_HEADERS, + () -> + Results.status( + CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) + .withHeader( + "X-Test-Response", + play.mvc.Http.Context.Implicit.request() + .getHeader("X-Test-Request"))), + HttpExecution.defaultContext())) + .GET(ERROR.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + ERROR, () -> Results.status(ERROR.getStatus(), ERROR.getBody())), + HttpExecution.defaultContext())) + .GET(EXCEPTION.getPath()) + .routeAsync( + () -> + CompletableFuture.supplyAsync( + () -> + controller( + EXCEPTION, + () -> { + throw new IllegalArgumentException(EXCEPTION.getBody()); + }), + HttpExecution.defaultContext())); + + return Server.forRouter(router.build(), port); + } +} diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java new file mode 100644 index 000000000000..02ddf42026fd --- /dev/null +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/server/PlayServerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4.server; + +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions; +import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.HttpAttributes; +import java.util.HashSet; +import java.util.Set; +import org.junit.jupiter.api.extension.RegisterExtension; +import play.mvc.Results; +import play.routing.RoutingDsl; +import play.server.Server; + +class PlayServerTest extends AbstractHttpServerTest { + + @RegisterExtension + static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent(); + + @Override + protected Server setupServer() { + RoutingDsl router = + new RoutingDsl() + .GET(SUCCESS.getPath()) + .routeTo( + () -> + controller( + SUCCESS, () -> Results.status(SUCCESS.getStatus(), SUCCESS.getBody()))) + .GET(INDEXED_CHILD.getPath()) + .routeTo( + () -> + controller( + INDEXED_CHILD, + () -> { + INDEXED_CHILD.collectSpanAttributes( + it -> play.mvc.Http.Context.Implicit.request().getQueryString(it)); + return Results.status(INDEXED_CHILD.getStatus()); + })) + .GET(QUERY_PARAM.getPath()) + .routeTo( + () -> + controller( + QUERY_PARAM, + () -> Results.status(QUERY_PARAM.getStatus(), QUERY_PARAM.getBody()))) + .GET(REDIRECT.getPath()) + .routeTo(() -> controller(REDIRECT, () -> Results.found(REDIRECT.getBody()))) + .GET(CAPTURE_HEADERS.getPath()) + .routeTo( + () -> + controller( + CAPTURE_HEADERS, + () -> + Results.status(CAPTURE_HEADERS.getStatus(), CAPTURE_HEADERS.getBody()) + .withHeader( + "X-Test-Response", + play.mvc.Http.Context.Implicit.request() + .getHeader("X-Test-Request")))) + .GET(ERROR.getPath()) + .routeTo( + () -> controller(ERROR, () -> Results.status(ERROR.getStatus(), ERROR.getBody()))) + .GET(EXCEPTION.getPath()) + .routeTo( + () -> + controller( + EXCEPTION, + () -> { + throw new IllegalArgumentException(EXCEPTION.getBody()); + })); + + return Server.forRouter(router.build(), port); + } + + @Override + protected void stopServer(Server server) { + server.stop(); + } + + @Override + protected void configure(HttpServerTestOptions options) { + options.setHasHandlerSpan(unused -> true); + options.setTestHttpPipelining(false); + options.setResponseCodeOnNonStandardHttpMethod(404); + options.setVerifyServerSpanEndTime( + false); // server spans are ended inside of the controller spans + options.setHttpAttributes( + serverEndpoint -> { + Set> attributes = + new HashSet<>(HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES); + attributes.remove(HttpAttributes.HTTP_ROUTE); + return attributes; + }); + + options.setExpectedException(new IllegalArgumentException(EXCEPTION.getBody())); + } + + @Override + public SpanDataAssert assertHandlerSpan( + SpanDataAssert span, String method, ServerEndpoint endpoint) { + span.hasName("play.request").hasKind(INTERNAL); + if (endpoint == EXCEPTION) { + span.hasStatus(StatusData.error()); + span.hasException(new IllegalArgumentException(EXCEPTION.getBody())); + } + return span; + } +}