Migrate Armeria server test to Java
DELETE
instrumentation/armeria-1.3/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.groovy
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.armeria.v1_3
-
-import com.linecorp.armeria.server.ServerBuilder
-import io.opentelemetry.instrumentation.armeria.v1_3.AbstractArmeriaHttpServerTest
-import io.opentelemetry.instrumentation.test.AgentTestTrait
-
-class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest implements AgentTestTrait {
- @Override
- ServerBuilder configureServer(ServerBuilder sb) {
- return sb
- }
-}

ADD
instrumentation/armeria-1.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.armeria.v1_3;
+
+import com.linecorp.armeria.server.ServerBuilder;
+import io.opentelemetry.instrumentation.armeria.v1_3.AbstractArmeriaHttpServerTest;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest {
+
+ @RegisterExtension
+ static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
+
+ @Override
+ protected ServerBuilder configureServer(ServerBuilder sb) {
+ return sb;
+ }
+}

DELETE
instrumentation/armeria-1.3/library/src/test/groovy/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.groovy
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.armeria.v1_3
-
-import com.linecorp.armeria.server.ServerBuilder
-import io.opentelemetry.instrumentation.test.LibraryTestTrait
-import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest
-
-class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest implements LibraryTestTrait {
- @Override
- ServerBuilder configureServer(ServerBuilder sb) {
- return sb.decorator(ArmeriaTracing.builder(getOpenTelemetry())
- .setCapturedServerRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER])
- .setCapturedServerResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER])
- .build()
- .newServiceDecorator())
- }
-}

ADD
instrumentation/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.armeria.v1_3;
+
+import com.linecorp.armeria.server.ServerBuilder;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
+import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
+import java.util.Collections;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest {
+
+ @RegisterExtension
+ static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forLibrary();
+
+ @Override
+ protected ServerBuilder configureServer(ServerBuilder sb) {
+ return sb.decorator(
+ ArmeriaTracing.builder(testing.getOpenTelemetry())
+ .setCapturedServerRequestHeaders(
+ Collections.singletonList(AbstractHttpServerTest.TEST_REQUEST_HEADER))
+ .setCapturedServerResponseHeaders(
+ Collections.singletonList(AbstractHttpServerTest.TEST_RESPONSE_HEADER))
+ .build()
+ .newServiceDecorator());
+ }
+}

MODIFY
instrumentation/armeria-1.3/testing/build.gradle.kts
instrumentation/armeria-1.3/testing/build.gradle.kts
@@ -7,10 +7,4 @@ dependencies {
api("com.linecorp.armeria:armeria:1.3.0")
api("com.linecorp.armeria:armeria-junit4:1.3.0")
-
- implementation("com.google.guava:guava")
-
- implementation("org.apache.groovy:groovy")
- implementation("io.opentelemetry:opentelemetry-api")
- implementation("org.spockframework:spock-core")
}

DELETE
instrumentation/armeria-1.3/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_3/AbstractArmeriaHttpServerTest.groovy
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.armeria.v1_3
-
-import com.linecorp.armeria.common.HttpData
-import com.linecorp.armeria.common.HttpHeaderNames
-import com.linecorp.armeria.common.HttpRequest
-import com.linecorp.armeria.common.HttpResponse
-import com.linecorp.armeria.common.HttpStatus
-import com.linecorp.armeria.common.MediaType
-import com.linecorp.armeria.common.QueryParams
-import com.linecorp.armeria.common.ResponseHeaders
-import com.linecorp.armeria.server.DecoratingHttpServiceFunction
-import com.linecorp.armeria.server.HttpService
-import com.linecorp.armeria.server.Server
-import com.linecorp.armeria.server.ServerBuilder
-import com.linecorp.armeria.server.ServiceRequestContext
-import io.opentelemetry.api.common.AttributeKey
-import io.opentelemetry.api.trace.Span
-import io.opentelemetry.instrumentation.test.base.HttpServerTest
-import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import java.util.function.Function
-
-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.NOT_FOUND
-import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.PATH_PARAM
-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
-
-abstract class AbstractArmeriaHttpServerTest extends HttpServerTest<Server> {
-
- abstract ServerBuilder configureServer(ServerBuilder serverBuilder)
-
- @Override
- String expectedHttpRoute(ServerEndpoint endpoint) {
- switch (endpoint) {
- case NOT_FOUND:
- // TODO(anuraaga): Revisit this when applying instrumenters to more libraries, Armeria
- // currently reports '/*' which is a fallback route.
- return "/*"
- default:
- return super.expectedHttpRoute(endpoint)
- }
- }
-
- @Override
- Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
- Set<AttributeKey<?>> extra = [
- SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH,
- SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH,
- SemanticAttributes.HTTP_SERVER_NAME
- ]
- super.httpAttributes(endpoint) + extra
- }
-
- @Override
- Server startServer(int port) {
- ServerBuilder sb = Server.builder()
-
- sb.http(port)
-
- sb.service(SUCCESS.path) { ctx, req ->
- controller(SUCCESS) {
- HttpResponse.of(HttpStatus.valueOf(SUCCESS.status), MediaType.PLAIN_TEXT_UTF_8, SUCCESS.body)
- }
- }
-
- sb.service(REDIRECT.path) { ctx, req ->
- controller(REDIRECT) {
- HttpResponse.of(ResponseHeaders.of(HttpStatus.valueOf(REDIRECT.status), HttpHeaderNames.LOCATION, REDIRECT.body))
- }
- }
-
- sb.service(ERROR.path) { ctx, req ->
- controller(ERROR) {
- HttpResponse.of(HttpStatus.valueOf(ERROR.status), MediaType.PLAIN_TEXT_UTF_8, ERROR.body)
- }
- }
-
- sb.service(EXCEPTION.path) { ctx, req ->
- controller(EXCEPTION) {
- throw new Exception(EXCEPTION.body)
- }
- }
-
- sb.service("/query") { ctx, req ->
- controller(QUERY_PARAM) {
- HttpResponse.of(HttpStatus.valueOf(QUERY_PARAM.status), MediaType.PLAIN_TEXT_UTF_8, "some=${QueryParams.fromQueryString(ctx.query()).get("some")}")
- }
- }
-
- sb.service("/path/:id/param") { ctx, req ->
- controller(PATH_PARAM) {
- HttpResponse.of(HttpStatus.valueOf(PATH_PARAM.status), MediaType.PLAIN_TEXT_UTF_8, ctx.pathParam("id"))
- }
- }
-
- sb.service("/child") { ctx, req ->
- controller(INDEXED_CHILD) {
- INDEXED_CHILD.collectSpanAttributes { QueryParams.fromQueryString(ctx.query()).get(it) }
- HttpResponse.of(HttpStatus.valueOf(INDEXED_CHILD.status), MediaType.PLAIN_TEXT_UTF_8, INDEXED_CHILD.body)
- }
- }
-
- sb.service("/captureHeaders") { ctx, req ->
- controller(CAPTURE_HEADERS) {
- HttpResponse.of(
- ResponseHeaders.of(HttpStatus.valueOf(CAPTURE_HEADERS.status),
- "X-Test-Response", req.headers().get("X-Test-Request"),
- HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8),
- HttpData.ofUtf8(CAPTURE_HEADERS.body))
- }
- }
-
- // Make sure user decorators see spans.
- sb.decorator(new DecoratingHttpServiceFunction() {
- @Override
- HttpResponse serve(HttpService delegate, ServiceRequestContext ctx, HttpRequest req) throws Exception {
- if (!Span.current().spanContext.isValid()) {
- // Return an invalid code to fail any assertion
- return HttpResponse.of(600)
- }
- ctx.addAdditionalResponseHeader("decoratinghttpservicefunction", "ok")
- return delegate.serve(ctx, req)
- }
- })
-
- sb.decorator(new Function<HttpService, HttpService>() {
- @Override
- HttpService apply(HttpService delegate) {
- return new HttpService() {
- @Override
- HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
- if (!Span.current().spanContext.isValid()) {
- // Return an invalid code to fail any assertion
- return HttpResponse.of(601)
- }
- ctx.addAdditionalResponseHeader("decoratingfunction", "ok")
- return delegate.serve(ctx, req)
- }
- }
- }
- })
-
- configureServer(sb)
-
- def server = sb.build()
- server.start().join()
- return server
- }
-
- @Override
- void stopServer(Server server) {
- server.stop()
- }
-
- @Override
- boolean testPathParam() {
- true
- }
-}

ADD
instrumentation/armeria-1.3/testing/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/AbstractArmeriaHttpServerTest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.armeria.v1_3;
+
+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.PATH_PARAM;
+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 com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.common.QueryParams;
+import com.linecorp.armeria.common.ResponseHeaders;
+import com.linecorp.armeria.server.Server;
+import com.linecorp.armeria.server.ServerBuilder;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
+import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
+import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class AbstractArmeriaHttpServerTest extends AbstractHttpServerTest<Server> {
+
+ protected abstract ServerBuilder configureServer(ServerBuilder serverBuilder);
+
+ @Override
+ protected Server setupServer() {
+ ServerBuilder sb = Server.builder();
+
+ sb.http(port);
+
+ sb.service(
+ SUCCESS.getPath(),
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ HttpStatus.valueOf(SUCCESS.getStatus()),
+ MediaType.PLAIN_TEXT_UTF_8,
+ SUCCESS.getBody())));
+
+ sb.service(
+ REDIRECT.getPath(),
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ ResponseHeaders.of(
+ HttpStatus.valueOf(REDIRECT.getStatus()),
+ HttpHeaderNames.LOCATION,
+ REDIRECT.getBody()))));
+
+ sb.service(
+ ERROR.getPath(),
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ HttpStatus.valueOf(ERROR.getStatus()),
+ MediaType.PLAIN_TEXT_UTF_8,
+ ERROR.getBody())));
+
+ sb.service(
+ EXCEPTION.getPath(),
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () -> {
+ throw new Exception(EXCEPTION.getBody());
+ }));
+
+ sb.service(
+ "/query",
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ HttpStatus.valueOf(QUERY_PARAM.getStatus()),
+ MediaType.PLAIN_TEXT_UTF_8,
+ "some=" + QueryParams.fromQueryString(ctx.query()).get("some"))));
+
+ sb.service(
+ "/path/:id/param",
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ HttpStatus.valueOf(PATH_PARAM.getStatus()),
+ MediaType.PLAIN_TEXT_UTF_8,
+ ctx.pathParam("id"))));
+
+ sb.service(
+ "/child",
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () -> {
+ INDEXED_CHILD.collectSpanAttributes(
+ name -> QueryParams.fromQueryString(ctx.query()).get(name));
+ return HttpResponse.of(
+ HttpStatus.valueOf(INDEXED_CHILD.getStatus()),
+ MediaType.PLAIN_TEXT_UTF_8,
+ INDEXED_CHILD.getBody());
+ }));
+
+ sb.service(
+ "/captureHeaders",
+ (ctx, req) ->
+ testing()
+ .runWithSpan(
+ "controller",
+ () ->
+ HttpResponse.of(
+ ResponseHeaders.of(
+ HttpStatus.valueOf(CAPTURE_HEADERS.getStatus()),
+ "X-Test-Response",
+ req.headers().get("X-Test-Request"),
+ HttpHeaderNames.CONTENT_TYPE,
+ MediaType.PLAIN_TEXT_UTF_8),
+ HttpData.ofUtf8(CAPTURE_HEADERS.getBody()))));
+
+ // Make sure user decorators see spans.
+ sb.decorator(
+ (delegate, ctx, req) -> {
+ if (!Span.current().getSpanContext().isValid()) {
+ // Return an invalid code to fail any assertion
+ return HttpResponse.of(600);
+ }
+ ctx.addAdditionalResponseHeader("decoratinghttpservicefunction", "ok");
+ return delegate.serve(ctx, req);
+ });
+
+ sb.decorator(
+ delegate ->
+ (ctx, req) -> {
+ if (!Span.current().getSpanContext().isValid()) {
+ // Return an invalid code to fail any assertion
+ return HttpResponse.of(601);
+ }
+ ctx.addAdditionalResponseHeader("decoratingfunction", "ok");
+ return delegate.serve(ctx, req);
+ });
+
+ configureServer(sb);
+
+ Server server = sb.build();
+ server.start().join();
+
+ return server;
+ }
+
+ @Override
+ protected void stopServer(Server server) {
+ server.stop();
+ }
+
+ @Override
+ protected final void configure(HttpServerTestOptions options) {
+ options.setExpectedHttpRoute(
+ endpoint -> {
+ if (endpoint == ServerEndpoint.NOT_FOUND) {
+ // TODO(anuraaga): Revisit this when applying instrumenters to more libraries, Armeria
+ // currently reports '/*' which is a fallback route.
+ return "/*";
+ }
+ return expectedHttpRoute(endpoint);
+ });
+
+ options.setHttpAttributes(
+ endpoint -> {
+ Set<AttributeKey<?>> keys = new HashSet<>(HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES);
+ keys.add(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH);
+ keys.add(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH);
+ keys.add(SemanticAttributes.HTTP_SERVER_NAME);
+ return keys;
+ });
+
+ options.setTestPathParam(true);
+ }
+}

MODIFY
testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java
testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java
@@ -81,6 +81,10 @@ public abstract class AbstractHttpServerTest<SERVER> {
protected abstract void stopServer(SERVER server);
+ protected final InstrumentationTestRunner testing() {
+ return testing;
+ }
+
@BeforeAll
void setupOptions() {
options.expectedServerSpanNameMapper = this::expectedServerSpanName;
@@ -511,8 +515,13 @@ public abstract class AbstractHttpServerTest<SERVER> {
SpanDataAssert span, String method, ServerEndpoint endpoint) {
Set<AttributeKey<?>> httpAttributes = options.httpAttributes.apply(endpoint);
- span.hasName(options.expectedServerSpanNameMapper.apply(endpoint, method))
- .hasKind(SpanKind.SERVER);
+ String expectedRoute = options.expectedHttpRoute.apply(endpoint);
+ String name =
+ expectedRoute != null
+ ? expectedRoute
+ : options.expectedServerSpanNameMapper.apply(endpoint, method);
+
+ span.hasName(name).hasKind(SpanKind.SERVER);
if (endpoint.status >= 500) {
span.hasStatus(StatusData.error());
}
@@ -593,7 +602,6 @@ public abstract class AbstractHttpServerTest<SERVER> {
entry -> assertThat(entry).isInstanceOf(String.class));
}
if (httpAttributes.contains(SemanticAttributes.HTTP_ROUTE)) {
- String expectedRoute = options.expectedHttpRoute.apply(endpoint);
if (expectedRoute != null) {
assertThat(attrs).containsEntry(SemanticAttributes.HTTP_ROUTE, expectedRoute);
}

Migrate Armeria server test to Java (#5570)