From 60aaff89721620030f53c8a21199124b146779e8 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 11 Jun 2021 08:56:02 +0900 Subject: [PATCH] Migrate HttpServerTest to Armeria (#3240) * Migrate HttpServerTest to Armeria * Update testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTest.groovy Co-authored-by: Trask Stalnaker Co-authored-by: Trask Stalnaker --- .../apachecamel/SingleServiceCamelTest.groovy | 16 +- .../src/main/groovy/ArquillianRestTest.groovy | 19 +-- .../src/test/groovy/CxfFilterTest.groovy | 9 +- .../main/groovy/JaxRsHttpServerTest.groovy | 87 +++------- .../src/main/groovy/BaseJsfTest.groovy | 76 ++++----- .../src/test/groovy/Netty38ServerTest.groovy | 4 + .../src/test/groovy/Netty40ServerTest.groovy | 6 +- .../src/test/groovy/Netty41ServerTest.groovy | 6 +- .../src/test/groovy/RatpackOtherTest.groovy | 88 +++++----- .../groovy/AbstractServlet3MappingTest.groovy | 8 +- .../test/groovy/AbstractServlet3Test.groovy | 7 +- .../src/test/groovy/TomcatServlet3Test.groovy | 23 ++- .../groovy/AbstractServlet5MappingTest.groovy | 8 +- .../test/groovy/AbstractServlet5Test.groovy | 7 +- .../src/test/groovy/TomcatServlet5Test.groovy | 23 ++- .../test/boot/SpringBootBasedTest.groovy | 27 +-- .../test/groovy/Struts2ActionSpanTest.groovy | 10 +- .../src/test/groovy/UndertowServerTest.groovy | 20 +-- .../src/test/groovy/WicketTest.groovy | 27 +-- .../test/base/HttpServerTest.groovy | 156 +++++++----------- .../test/base/HttpServerTestTrait.groovy | 17 +- 21 files changed, 256 insertions(+), 388 deletions(-) diff --git a/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/SingleServiceCamelTest.groovy b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/SingleServiceCamelTest.groovy index a881ff0469..ff3d79f734 100644 --- a/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/SingleServiceCamelTest.groovy +++ b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/SingleServiceCamelTest.groovy @@ -9,13 +9,9 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait -import io.opentelemetry.instrumentation.test.utils.OkHttpUtils import io.opentelemetry.instrumentation.test.utils.PortUtils import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import okhttp3.FormBody -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request +import io.opentelemetry.testing.armeria.client.WebClient import org.springframework.boot.SpringApplication import org.springframework.context.ConfigurableApplicationContext import spock.lang.Shared @@ -25,7 +21,7 @@ class SingleServiceCamelTest extends AgentInstrumentationSpecification implement @Shared ConfigurableApplicationContext server @Shared - OkHttpClient client = OkHttpUtils.client() + WebClient client = WebClient.of() @Shared int port @Shared @@ -56,15 +52,9 @@ class SingleServiceCamelTest extends AgentInstrumentationSpecification implement def "single camel service span"() { setup: def requestUrl = address.resolve("/camelService") - def url = HttpUrl.get(requestUrl) - def request = new Request.Builder() - .url(url) - .method("POST", - new FormBody.Builder().add("", "testContent").build()) - .build() when: - client.newCall(request).execute() + client.post(requestUrl.toString(), "testContent").aggregate().join() then: assertTraces(1) { diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-arquillian-testing/src/main/groovy/ArquillianRestTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-arquillian-testing/src/main/groovy/ArquillianRestTest.groovy index b5dba86635..ce393a52b8 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-arquillian-testing/src/main/groovy/ArquillianRestTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-arquillian-testing/src/main/groovy/ArquillianRestTest.groovy @@ -6,11 +6,8 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.instrumentation.test.utils.OkHttpUtils -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response +import io.opentelemetry.testing.armeria.client.WebClient +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import org.jboss.arquillian.container.test.api.Deployment import org.jboss.arquillian.container.test.api.RunAsClient import org.jboss.arquillian.spock.ArquillianSputnik @@ -28,7 +25,7 @@ import test.RestApplication @RunAsClient abstract class ArquillianRestTest extends AgentInstrumentationSpecification { - static OkHttpClient client = OkHttpUtils.client() + static WebClient client = WebClient.of() @ArquillianResource static URI url @@ -49,15 +46,11 @@ abstract class ArquillianRestTest extends AgentInstrumentationSpecification { @Unroll def "test #path"() { when: - Request request = new Request.Builder().url(HttpUrl.get(url.resolve(path))).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(url.resolve(path).toString()).aggregate().join() then: - response.withCloseable { - assert response.code() == 200 - assert response.body().string() == "hello" - true - } + response.status().code() == 200 + response.contentUtf8() == "hello" and: assertTraces(1) { diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfFilterTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfFilterTest.groovy index d0b6b01b8d..feb9465caa 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfFilterTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfFilterTest.groovy @@ -8,11 +8,10 @@ import static Resource.Test2 import static Resource.Test3 import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait -import okhttp3.FormBody +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import okhttp3.HttpUrl import okhttp3.Request import okhttp3.RequestBody -import okhttp3.Response import org.apache.cxf.endpoint.Server import org.apache.cxf.jaxrs.JAXRSServerFactoryBean @@ -54,10 +53,8 @@ class CxfFilterTest extends JaxRsFilterTest implements HttpServerTestTrait extends HttpServerTest implements Agent def "test super method without @Path"() { given: - def url = HttpUrl.get(address.resolve("test-resource-super")).newBuilder() - .build() - def request = request(url, "GET", null).build() - def response = client.newCall(request).execute() + def response = client.get(address.resolve("test-resource-super").toString()).aggregate().join() expect: - response.withCloseable { - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body - true - } + response.status().code() == SUCCESS.status + response.contentUtf8() == SUCCESS.body assertTraces(1) { trace(0, 2) { @@ -59,17 +47,11 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent assumeTrue(testInterfaceMethodWithPath()) given: - def url = HttpUrl.get(address.resolve("test-resource-interface/call")).newBuilder() - .build() - def request = request(url, "GET", null).build() - def response = client.newCall(request).execute() + def response = client.get(address.resolve("test-resource-interface/call").toString()).aggregate().join() expect: - response.withCloseable { - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body - true - } + response.status().code() == SUCCESS.status + response.contentUtf8() == SUCCESS.body assertTraces(1) { trace(0, 2) { @@ -85,17 +67,11 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent def "test sub resource locator"() { given: - def url = HttpUrl.get(address.resolve("test-sub-resource-locator/call/sub")).newBuilder() - .build() - def request = request(url, "GET", null).build() - def response = client.newCall(request).execute() + def response = client.get(address.resolve("test-sub-resource-locator/call/sub").toString()).aggregate().join() expect: - response.withCloseable { - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body - true - } + response.status().code() == SUCCESS.status + response.contentUtf8() == SUCCESS.body assertTraces(1) { trace(0, 5) { @@ -115,13 +91,10 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent @Unroll def "should handle #desc AsyncResponse"() { given: - def url = HttpUrl.get(address.resolve("async")).newBuilder() - .addQueryParameter("action", action) - .build() - def request = request(url, "GET", null).build() + def url = address.resolve("async?action=${action}").toString() when: "async call is started" - def futureResponse = asyncCall(request) + def futureResponse = client.get(url).aggregate() then: "there are no traces yet" assertTraces(0) { @@ -132,8 +105,8 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent def response = futureResponse.join() then: - assert response.code() == statusCode - assert bodyPredicate(response.body().string()) + response.status().code() == statusCode + bodyPredicate(response.contentUtf8()) def spanCount = 2 def hasSendError = asyncCancelHasSendError() && action == "cancel" @@ -160,15 +133,11 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent @Unroll def "should handle #desc CompletionStage (JAX-RS 2.1+ only)"() { assumeTrue(shouldTestCompletableStageAsync()) - given: - def url = HttpUrl.get(address.resolve("async-completion-stage")).newBuilder() - .addQueryParameter("action", action) - .build() - def request = request(url, "GET", null).build() + def url = address.resolve("async-completion-stage?action=${action}").toString() when: "async call is started" - def futureResponse = asyncCall(request) + def futureResponse = client.get(url).aggregate() then: "there are no traces yet" assertTraces(0) { @@ -179,8 +148,8 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent def response = futureResponse.join() then: - assert response.code() == statusCode - assert bodyPredicate(response.body().string()) + response.status().code() == statusCode + bodyPredicate(response.contentUtf8()) assertTraces(1) { trace(0, 2) { @@ -245,9 +214,9 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent void asyncServerSpan(TraceAssert trace, int index, - HttpUrl url, + String url, int statusCode) { - def rawUrl = url.url() + def rawUrl = URI.create(url).toURL() serverSpan(trace, index, null, null, "GET", rawUrl.path, rawUrl.toURI(), @@ -328,22 +297,4 @@ abstract class JaxRsHttpServerTest extends HttpServerTest implements Agent } } } - - private CompletableFuture asyncCall(Request request) { - def future = new CompletableFuture() - - client.newCall(request).enqueue(new Callback() { - @Override - void onFailure(Call call, IOException e) { - future.completeExceptionally(e) - } - - @Override - void onResponse(Call call, Response response) throws IOException { - future.complete(response) - } - }) - - return future - } } diff --git a/instrumentation/jsf/jsf-testing-common/src/main/groovy/BaseJsfTest.groovy b/instrumentation/jsf/jsf-testing-common/src/main/groovy/BaseJsfTest.groovy index b24ec76fbc..97ed4fbbd3 100644 --- a/instrumentation/jsf/jsf-testing-common/src/main/groovy/BaseJsfTest.groovy +++ b/instrumentation/jsf/jsf-testing-common/src/main/groovy/BaseJsfTest.groovy @@ -11,11 +11,13 @@ import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.sdk.trace.data.SpanData -import okhttp3.FormBody -import okhttp3.HttpUrl -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.Response +import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse +import io.opentelemetry.testing.armeria.common.HttpData +import io.opentelemetry.testing.armeria.common.HttpMethod +import io.opentelemetry.testing.armeria.common.MediaType +import io.opentelemetry.testing.armeria.common.QueryParams +import io.opentelemetry.testing.armeria.common.RequestHeaders import org.eclipse.jetty.annotations.AnnotationConfiguration import org.eclipse.jetty.server.Server import org.eclipse.jetty.util.resource.Resource @@ -72,13 +74,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements @Unroll def "test #path"() { setup: - def url = HttpUrl.get(address.resolve("hello.jsf")).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(address.resolve("hello.jsf").toString()).aggregate().join() expect: - response.code() == 200 - response.body().string().trim() == "Hello" + response.status().code() == 200 + response.contentUtf8().trim() == "Hello" and: assertTraces(1) { @@ -94,13 +94,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements def "test greeting"() { // we need to display the page first before posting data to it setup: - def url = HttpUrl.get(address.resolve("greeting.jsf")).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() - def doc = Jsoup.parse(response.body().string()) + AggregatedHttpResponse response = client.get(address.resolve("greeting.jsf").toString()).aggregate().join() + def doc = Jsoup.parse(response.contentUtf8()) expect: - response.code() == 200 + response.status().code() == 200 doc.selectFirst("title").text() == "Hello, World!" and: @@ -122,10 +120,8 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements jsessionid != null when: - // use the session created for first request - def url2 = HttpUrl.get(address.resolve("greeting.jsf;jsessionid=" + jsessionid)).newBuilder().build() // set up form parameter for post - RequestBody formBody = new FormBody.Builder() + QueryParams formBody = QueryParams.builder() .add("app-form", "app-form") // value used for name is returned in app-form:output-message element .add("app-form:name", "test") @@ -133,13 +129,18 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements .add("app-form_SUBMIT", "1") // MyFaces .add("javax.faces.ViewState", viewState) .build() - def request2 = this.request(url2, "POST", formBody).build() - Response response2 = client.newCall(request2).execute() - def responseContent = response2.body().string() + // use the session created for first request + def request2 = AggregatedHttpRequest.of( + RequestHeaders.builder(HttpMethod.POST, address.resolve("greeting.jsf;jsessionid=" + jsessionid).toString()) + .contentType(MediaType.FORM_DATA) + .build(), + HttpData.ofUtf8(formBody.toQueryString())) + AggregatedHttpResponse response2 = client.execute(request2).aggregate().join() + def responseContent = response2.contentUtf8() def doc2 = Jsoup.parse(responseContent) then: - response2.code() == 200 + response2.status().code() == 200 doc2.getElementById("app-form:output-message").text() == "Hello test" and: @@ -154,13 +155,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements def "test exception"() { // we need to display the page first before posting data to it setup: - def url = HttpUrl.get(address.resolve("greeting.jsf")).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() - def doc = Jsoup.parse(response.body().string()) + AggregatedHttpResponse response = client.get(address.resolve("greeting.jsf").toString()).aggregate().join() + def doc = Jsoup.parse(response.contentUtf8()) expect: - response.code() == 200 + response.status().code() == 200 doc.selectFirst("title").text() == "Hello, World!" and: @@ -182,10 +181,8 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements jsessionid != null when: - // use the session created for first request - def url2 = HttpUrl.get(address.resolve("greeting.jsf;jsessionid=" + jsessionid)).newBuilder().build() // set up form parameter for post - RequestBody formBody = new FormBody.Builder() + QueryParams formBody = QueryParams.builder() .add("app-form", "app-form") // setting name parameter to "exception" triggers throwing exception in GreetingForm .add("app-form:name", "exception") @@ -193,11 +190,16 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements .add("app-form_SUBMIT", "1") // MyFaces .add("javax.faces.ViewState", viewState) .build() - def request2 = this.request(url2, "POST", formBody).build() - Response response2 = client.newCall(request2).execute() + // use the session created for first request + def request2 = AggregatedHttpRequest.of( + RequestHeaders.builder(HttpMethod.POST, address.resolve("greeting.jsf;jsessionid=" + jsessionid).toString()) + .contentType(MediaType.FORM_DATA) + .build(), + HttpData.ofUtf8(formBody.toQueryString())) + AggregatedHttpResponse response2 = client.execute(request2).aggregate().join() then: - response2.code() == 500 + response2.status().code() == 500 and: assertTraces(1) { @@ -208,14 +210,6 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements } } - Request.Builder request(HttpUrl url, String method, RequestBody body) { - return new Request.Builder() - .url(url) - .method(method, body) - .header("User-Agent", TEST_USER_AGENT) - .header("X-Forwarded-For", TEST_CLIENT_IP) - } - void handlerSpan(TraceAssert trace, int index, Object parent, String spanName, Exception expectedException = null) { trace.span(index) { name spanName diff --git a/instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy b/instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy index 0de0f2fbbb..067d373df7 100644 --- a/instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy +++ b/instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy @@ -74,8 +74,10 @@ class Netty38ServerTest extends HttpServerTest implements Agent response.setContent(responseContent) break case INDEXED_CHILD: + responseContent = ChannelBuffers.EMPTY_BUFFER endpoint.collectSpanAttributes { new QueryStringDecoder(uri).getParameters().get(it).find() } response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + response.setContent(responseContent) break case QUERY_PARAM: responseContent = ChannelBuffers.copiedBuffer(uri.query, CharsetUtil.UTF_8) @@ -83,7 +85,9 @@ class Netty38ServerTest extends HttpServerTest implements Agent response.setContent(responseContent) break case REDIRECT: + responseContent = ChannelBuffers.EMPTY_BUFFER response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + response.setContent(responseContent) response.headers().set(LOCATION, endpoint.body) break case EXCEPTION: diff --git a/instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ServerTest.groovy b/instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ServerTest.groovy index 0e8d4a7a90..ec16802dcc 100644 --- a/instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ServerTest.groovy +++ b/instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ServerTest.groovy @@ -72,15 +72,17 @@ class Netty40ServerTest extends HttpServerTest implements AgentT response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case INDEXED_CHILD: + content = Unpooled.EMPTY_BUFFER endpoint.collectSpanAttributes { new QueryStringDecoder(uri).parameters().get(it).find() } - response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case QUERY_PARAM: content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case REDIRECT: - response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + content = Unpooled.EMPTY_BUFFER + response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response.headers().set(HttpHeaders.Names.LOCATION, endpoint.body) break case EXCEPTION: diff --git a/instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ServerTest.groovy b/instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ServerTest.groovy index 2c914937ef..d4bf07873d 100644 --- a/instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ServerTest.groovy +++ b/instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ServerTest.groovy @@ -71,15 +71,17 @@ class Netty41ServerTest extends HttpServerTest implements AgentT response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case INDEXED_CHILD: + content = Unpooled.EMPTY_BUFFER endpoint.collectSpanAttributes { new QueryStringDecoder(uri).parameters().get(it).find() } - response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case QUERY_PARAM: content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) break case REDIRECT: - response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) + content = Unpooled.EMPTY_BUFFER + response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response.headers().set(HttpHeaderNames.LOCATION, endpoint.body) break case EXCEPTION: diff --git a/instrumentation/ratpack-1.4/javaagent/src/test/groovy/RatpackOtherTest.groovy b/instrumentation/ratpack-1.4/javaagent/src/test/groovy/RatpackOtherTest.groovy index 5a09f6c440..0abe7b112a 100644 --- a/instrumentation/ratpack-1.4/javaagent/src/test/groovy/RatpackOtherTest.groovy +++ b/instrumentation/ratpack-1.4/javaagent/src/test/groovy/RatpackOtherTest.groovy @@ -7,66 +7,65 @@ import static io.opentelemetry.api.trace.SpanKind.INTERNAL import static io.opentelemetry.api.trace.SpanKind.SERVER import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.instrumentation.test.utils.OkHttpUtils import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request +import io.opentelemetry.testing.armeria.client.WebClient import ratpack.path.PathBinding import ratpack.server.RatpackServer +import spock.lang.Shared class RatpackOtherTest extends AgentInstrumentationSpecification { - OkHttpClient client = OkHttpUtils.client() - - def "test bindings for #path"() { - setup: - def app = RatpackServer.start { - it.handlers { - it.prefix("a") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + @Shared + RatpackServer app = RatpackServer.start { + it.handlers { + it.prefix("a") { + it.all {context -> + context.render(context.get(PathBinding).description) } - it.prefix("b/::\\d+") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + } + it.prefix("b/::\\d+") { + it.all {context -> + context.render(context.get(PathBinding).description) } - it.prefix("c/:val?") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + } + it.prefix("c/:val?") { + it.all {context -> + context.render(context.get(PathBinding).description) } - it.prefix("d/:val") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + } + it.prefix("d/:val") { + it.all {context -> + context.render(context.get(PathBinding).description) } - it.prefix("e/:val?:\\d+") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + } + it.prefix("e/:val?:\\d+") { + it.all {context -> + context.render(context.get(PathBinding).description) } - it.prefix("f/:val:\\d+") { - it.all {context -> - context.render(context.get(PathBinding).description) - } + } + it.prefix("f/:val:\\d+") { + it.all {context -> + context.render(context.get(PathBinding).description) } } } - def address = "${app.scheme}://${app.bindHost}:${app.bindPort}" - def request = new Request.Builder() - .url(HttpUrl.get(address).newBuilder().addPathSegments(path).build()) - .get() - .build() + } + // Force HTTP/1 with h1c to prevent tracing of upgrade request. + @Shared + WebClient client = WebClient.of("h1c://localhost:${app.bindPort}") + + def cleanupSpec() { + app.stop() + } + + def "test bindings for #path"() { when: - def resp = client.newCall(request).execute() + def resp = client.get(path).aggregate().join() then: - resp.code() == 200 - resp.body.string() == route + resp.status().code() == 200 + resp.contentUtf8() == route assertTraces(1) { trace(0, 2) { @@ -77,7 +76,7 @@ class RatpackOtherTest extends AgentInstrumentationSpecification { attributes { "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_PORT.key}" Long - "${SemanticAttributes.HTTP_URL.key}" "${address}/${path}" + "${SemanticAttributes.HTTP_URL.key}" "http://localhost:${app.bindPort}/${path}" "${SemanticAttributes.HTTP_METHOD.key}" "GET" "${SemanticAttributes.HTTP_STATUS_CODE.key}" 200 "${SemanticAttributes.HTTP_FLAVOR.key}" "1.1" @@ -95,9 +94,6 @@ class RatpackOtherTest extends AgentInstrumentationSpecification { } } - cleanup: - app.stop() - where: path | route "a" | "a" diff --git a/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3MappingTest.groovy b/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3MappingTest.groovy index 2ad93cefb3..87b116f62f 100644 --- a/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3MappingTest.groovy +++ b/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3MappingTest.groovy @@ -8,6 +8,7 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import javax.servlet.Servlet import javax.servlet.ServletException import javax.servlet.http.HttpServlet @@ -16,7 +17,6 @@ import javax.servlet.http.HttpServletResponse import okhttp3.HttpUrl import okhttp3.Request import okhttp3.RequestBody -import okhttp3.Response import spock.lang.Unroll abstract class AbstractServlet3MappingTest extends AgentInstrumentationSpecification implements HttpServerTestTrait { @@ -44,12 +44,10 @@ abstract class AbstractServlet3MappingTest extends AgentInstrum @Unroll def "test path #path"() { setup: - def url = HttpUrl.get(address.resolve(path)).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(address.resolve(path).toString()).aggregate().join() expect: - response.code() == success ? 200 : 404 + response.status().code() == success ? 200 : 404 and: def spanCount = success ? 1 : 2 diff --git a/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3Test.groovy b/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3Test.groovy index 79e1f57072..8d85f33725 100644 --- a/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3Test.groovy +++ b/instrumentation/servlet/servlet-3.0/javaagent/src/test/groovy/AbstractServlet3Test.groovy @@ -14,9 +14,8 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.base.HttpServerTest +import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest import javax.servlet.Servlet -import okhttp3.Request -import okhttp3.RequestBody abstract class AbstractServlet3Test extends HttpServerTest implements AgentTestTrait { @Override @@ -49,9 +48,9 @@ abstract class AbstractServlet3Test extends HttpServerTest def "access log has ids for #count requests"() { given: - def request = request(SUCCESS, method, body).build() + def request = request(SUCCESS, method) when: - List responses = (1..count).collect { - return client.newCall(request).execute() + List responses = (1..count).collect { + return client.execute(request).aggregate().join() } then: responses.each { response -> - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body + assert response.status().code() == SUCCESS.status + assert response.contentUtf8() == SUCCESS.body } and: @@ -150,19 +151,18 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test where: method = "GET" - body = null count << [1, 4] // make multiple requests. } def "access log has ids for error request"() { setup: assumeTrue(testError()) - def request = request(ERROR, method, body).build() - def response = client.newCall(request).execute() + def request = request(ERROR, method) + def response = client.execute(request).aggregate().join() expect: - response.code() == ERROR.status - response.body().string() == ERROR.body + response.status().code() == ERROR.status + response.contentUtf8() == ERROR.body and: def spanCount = 2 @@ -171,7 +171,7 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test } assertTraces(1) { trace(0, spanCount) { - serverSpan(it, 0, null, null, method, response.body().contentLength(), ERROR) + serverSpan(it, 0, null, null, method, response.content().length(), ERROR) def spanIndex = 1 controllerSpan(it, spanIndex, span(spanIndex - 1)) spanIndex++ @@ -189,7 +189,6 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test where: method = "GET" - body = null } // FIXME: Add authentication tests back in... diff --git a/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5MappingTest.groovy b/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5MappingTest.groovy index 6c1edf8013..ac9a3f09e1 100644 --- a/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5MappingTest.groovy +++ b/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5MappingTest.groovy @@ -8,6 +8,7 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import jakarta.servlet.Servlet import jakarta.servlet.ServletException import jakarta.servlet.http.HttpServlet @@ -16,7 +17,6 @@ import jakarta.servlet.http.HttpServletResponse import okhttp3.HttpUrl import okhttp3.Request import okhttp3.RequestBody -import okhttp3.Response import spock.lang.Unroll abstract class AbstractServlet5MappingTest extends AgentInstrumentationSpecification implements HttpServerTestTrait { @@ -44,12 +44,10 @@ abstract class AbstractServlet5MappingTest extends AgentInstrum @Unroll def "test path #path"() { setup: - def url = HttpUrl.get(address.resolve(path)).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(address.resolve(path).toString()).aggregate().join() expect: - response.code() == success ? 200 : 404 + response.status().code() == (success ? 200 : 404) and: def spanCount = success ? 1 : 2 diff --git a/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5Test.groovy b/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5Test.groovy index f0c83c731b..c26af43499 100644 --- a/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5Test.groovy +++ b/instrumentation/servlet/servlet-5.0/javaagent/src/test/groovy/AbstractServlet5Test.groovy @@ -14,9 +14,8 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.base.HttpServerTest +import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest import jakarta.servlet.Servlet -import okhttp3.Request -import okhttp3.RequestBody abstract class AbstractServlet5Test extends HttpServerTest implements AgentTestTrait { @Override @@ -49,9 +48,9 @@ abstract class AbstractServlet5Test extends HttpServerTest def "access log has ids for #count requests"() { given: - def request = request(SUCCESS, method, body).build() + def request = request(SUCCESS, method) when: - List responses = (1..count).collect { - return client.newCall(request).execute() + List responses = (1..count).collect { + return client.execute(request).aggregate().join() } then: responses.each { response -> - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body + assert response.status().code() == SUCCESS.status + assert response.contentUtf8() == SUCCESS.body } and: @@ -150,19 +151,18 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test where: method = "GET" - body = null count << [1, 4] // make multiple requests. } def "access log has ids for error request"() { setup: assumeTrue(testError()) - def request = request(ERROR, method, body).build() - def response = client.newCall(request).execute() + def request = request(ERROR, method) + def response = client.execute(request).aggregate().join() expect: - response.code() == ERROR.status - response.body().string() == ERROR.body + response.status().code() == ERROR.status + response.contentUtf8() == ERROR.body and: def spanCount = 2 @@ -171,7 +171,7 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test } assertTraces(1) { trace(0, spanCount) { - serverSpan(it, 0, null, null, method, response.body().contentLength(), ERROR) + serverSpan(it, 0, null, null, method, response.content().length(), ERROR) def spanIndex = 1 controllerSpan(it, spanIndex, span(spanIndex - 1)) spanIndex++ @@ -189,7 +189,6 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test where: method = "GET" - body = null } // FIXME: Add authentication tests back in... diff --git a/instrumentation/spring/spring-webmvc-3.1/javaagent/src/test/groovy/test/boot/SpringBootBasedTest.groovy b/instrumentation/spring/spring-webmvc-3.1/javaagent/src/test/groovy/test/boot/SpringBootBasedTest.groovy index 203d3d5af2..5a70ddda3a 100644 --- a/instrumentation/spring/spring-webmvc-3.1/javaagent/src/test/groovy/test/boot/SpringBootBasedTest.groovy +++ b/instrumentation/spring/spring-webmvc-3.1/javaagent/src/test/groovy/test/boot/SpringBootBasedTest.groovy @@ -19,8 +19,10 @@ import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.sdk.trace.data.SpanData -import okhttp3.FormBody -import okhttp3.RequestBody +import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest +import io.opentelemetry.testing.armeria.common.HttpData +import io.opentelemetry.testing.armeria.common.MediaType +import io.opentelemetry.testing.armeria.common.QueryParams import org.springframework.boot.SpringApplication import org.springframework.context.ConfigurableApplicationContext import org.springframework.web.servlet.view.RedirectView @@ -91,14 +93,14 @@ class SpringBootBasedTest extends HttpServerTest def "test spans with auth error"() { setup: def authProvider = server.getBean(SavingAuthenticationProvider) - def request = request(AUTH_ERROR, "GET", null).build() + def request = request(AUTH_ERROR, "GET") when: authProvider.latestAuthentications.clear() - def response = client.newCall(request).execute() + def response = client.execute(request).aggregate().join() then: - response.code() == 401 // not secured + response.status().code() == 401 // not secured and: assertTraces(1) { @@ -114,24 +116,23 @@ class SpringBootBasedTest extends HttpServerTest setup: def authProvider = server.getBean(SavingAuthenticationProvider) - RequestBody formBody = new FormBody.Builder() - .add("username", "test") - .add("password", testPassword).build() - - def request = request(LOGIN, "POST", formBody).build() + QueryParams form = QueryParams.of("username", "test", "password", testPassword) + def request = AggregatedHttpRequest.of( + request(LOGIN, "POST").headers().toBuilder().contentType(MediaType.FORM_DATA).build(), + HttpData.ofUtf8(form.toQueryString())) when: authProvider.latestAuthentications.clear() - def response = client.newCall(request).execute() + def response = client.execute(request).aggregate().join() then: - response.code() == 302 // redirect after success + response.status().code() == 302 // redirect after success authProvider.latestAuthentications.get(0).password == testPassword and: assertTraces(1) { trace(0, 2) { - serverSpan(it, 0, null, null, "POST", response.body()?.contentLength(), LOGIN) + serverSpan(it, 0, null, null, "POST", response.contentUtf8().length(), LOGIN) redirectSpan(it, 1, span(0)) } } diff --git a/instrumentation/struts-2.3/javaagent/src/test/groovy/Struts2ActionSpanTest.groovy b/instrumentation/struts-2.3/javaagent/src/test/groovy/Struts2ActionSpanTest.groovy index 9b5ddd6dc9..7e1afa5f10 100644 --- a/instrumentation/struts-2.3/javaagent/src/test/groovy/Struts2ActionSpanTest.groovy +++ b/instrumentation/struts-2.3/javaagent/src/test/groovy/Struts2ActionSpanTest.groovy @@ -20,7 +20,6 @@ import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.struts.GreetingServlet import javax.servlet.DispatcherType -import okhttp3.HttpUrl import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.DefaultServlet @@ -125,14 +124,11 @@ class Struts2ActionSpanTest extends HttpServerTest implements AgentTestT // does not overwrite server span name given by struts instrumentation. def "test dispatch to servlet"() { setup: - def url = HttpUrl.get(address.resolve("dispatch")).newBuilder() - .build() - def request = request(url, "GET", null).build() - def response = client.newCall(request).execute() + def response = client.get(address.resolve("dispatch").toString()).aggregate().join() expect: - response.code() == 200 - response.body().string() == "greeting" + response.status().code() == 200 + response.contentUtf8() == "greeting" and: assertTraces(1) { diff --git a/instrumentation/undertow-1.4/javaagent/src/test/groovy/UndertowServerTest.groovy b/instrumentation/undertow-1.4/javaagent/src/test/groovy/UndertowServerTest.groovy index 5e12fd9e78..5c1c8249de 100644 --- a/instrumentation/undertow-1.4/javaagent/src/test/groovy/UndertowServerTest.groovy +++ b/instrumentation/undertow-1.4/javaagent/src/test/groovy/UndertowServerTest.groovy @@ -17,13 +17,11 @@ import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.semconv.trace.attributes.SemanticAttributes +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import io.undertow.Handlers import io.undertow.Undertow import io.undertow.util.Headers import io.undertow.util.StatusCodes -import okhttp3.HttpUrl -import okhttp3.Response - //TODO make test which mixes handlers and servlets class UndertowServerTest extends HttpServerTest implements AgentTestTrait { @@ -99,13 +97,11 @@ class UndertowServerTest extends HttpServerTest implements AgentTestTr def "test send response"() { setup: def uri = address.resolve("sendResponse") - def url = HttpUrl.get(uri).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join() expect: - response.code() == 200 - response.body().string().trim() == "sendResponse" + response.status().code() == 200 + response.contentUtf8().trim() == "sendResponse" and: assertTraces(1) { @@ -141,13 +137,11 @@ class UndertowServerTest extends HttpServerTest implements AgentTestTr def "test send response with exception"() { setup: def uri = address.resolve("sendResponseWithException") - def url = HttpUrl.get(uri).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join() expect: - response.code() == 200 - response.body().string().trim() == "sendResponseWithException" + response.status().code() == 200 + response.contentUtf8().trim() == "sendResponseWithException" and: assertTraces(1) { diff --git a/instrumentation/wicket-8.0/javaagent/src/test/groovy/WicketTest.groovy b/instrumentation/wicket-8.0/javaagent/src/test/groovy/WicketTest.groovy index b497ceb55c..abf169b4e6 100644 --- a/instrumentation/wicket-8.0/javaagent/src/test/groovy/WicketTest.groovy +++ b/instrumentation/wicket-8.0/javaagent/src/test/groovy/WicketTest.groovy @@ -8,11 +8,8 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicServer import hello.HelloApplication import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse import javax.servlet.DispatcherType -import okhttp3.HttpUrl -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.Response import org.apache.wicket.protocol.http.WicketFilter import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.DefaultServlet @@ -55,13 +52,11 @@ class WicketTest extends AgentInstrumentationSpecification implements HttpServer def "test hello"() { setup: - def url = HttpUrl.get(address.resolve("wicket-test/")).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() - def doc = Jsoup.parse(response.body().string()) + AggregatedHttpResponse response = client.get(address.resolve("wicket-test/").toString()).aggregate().join() + def doc = Jsoup.parse(response.contentUtf8()) expect: - response.code() == 200 + response.status().code() == 200 doc.selectFirst("#message").text() == "Hello World!" assertTraces(1) { @@ -73,12 +68,10 @@ class WicketTest extends AgentInstrumentationSpecification implements HttpServer def "test exception"() { setup: - def url = HttpUrl.get(address.resolve("wicket-test/exception")).newBuilder().build() - def request = request(url, "GET", null).build() - Response response = client.newCall(request).execute() + AggregatedHttpResponse response = client.get(address.resolve("wicket-test/exception").toString()).aggregate().join() expect: - response.code() == 500 + response.status().code() == 500 assertTraces(1) { trace(0, 1) { @@ -86,12 +79,4 @@ class WicketTest extends AgentInstrumentationSpecification implements HttpServer } } } - - Request.Builder request(HttpUrl url, String method, RequestBody body) { - return new Request.Builder() - .url(url) - .method(method, body) - .header("User-Agent", TEST_USER_AGENT) - .header("X-Forwarded-For", TEST_CLIENT_IP) - } } diff --git a/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTest.groovy b/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTest.groovy index 66684f170e..331ef884d1 100644 --- a/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTest.groovy +++ b/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTest.groovy @@ -5,7 +5,6 @@ package io.opentelemetry.instrumentation.test.base - import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.ERROR import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.EXCEPTION import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.INDEXED_CHILD @@ -29,13 +28,14 @@ import io.opentelemetry.instrumentation.test.InstrumentationSpecification import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.semconv.trace.attributes.SemanticAttributes +import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest +import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse +import io.opentelemetry.testing.armeria.common.HttpMethod +import io.opentelemetry.testing.armeria.common.HttpRequest +import io.opentelemetry.testing.armeria.common.HttpRequestBuilder import java.util.concurrent.Callable import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors -import okhttp3.HttpUrl -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.Response import spock.lang.Unroll @Unroll @@ -207,20 +207,14 @@ abstract class HttpServerTest extends InstrumentationSpecification imple } } - Request.Builder request(ServerEndpoint uri, String method, RequestBody body) { - def url = HttpUrl.get(uri.resolvePath(address)).newBuilder() - .query(uri.query) - .fragment(uri.fragment) - .build() - return request(url, method, body) - } - - Request.Builder request(HttpUrl url, String method, RequestBody body) { - return new Request.Builder() - .url(url) - .method(method, body) - .header("User-Agent", TEST_USER_AGENT) - .header("X-Forwarded-For", TEST_CLIENT_IP) + AggregatedHttpRequest request(ServerEndpoint uri, String method) { + def url = uri.resolvePath(address).toString() + // Force HTTP/1 via h1c so upgrade requests don't show up as traces + url = url.replace("http://", "h1c://") + if (uri.query != null) { + url += "?${uri.query}" + } + return AggregatedHttpRequest.of(HttpMethod.valueOf(method), url) } static T controller(ServerEndpoint endpoint, Callable closure) { @@ -233,17 +227,15 @@ abstract class HttpServerTest extends InstrumentationSpecification imple def "test success with #count requests"() { setup: - def request = request(SUCCESS, method, body).build() - List responses = (1..count).collect { - return client.newCall(request).execute() + def request = request(SUCCESS, method) + List responses = (1..count).collect { + return client.execute(request).aggregate().join() } expect: responses.each { response -> - response.withCloseable { - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body - } + assert response.status().code() == SUCCESS.status + assert response.contentUtf8() == SUCCESS.body } and: @@ -251,7 +243,6 @@ abstract class HttpServerTest extends InstrumentationSpecification imple where: method = "GET" - body = null count << [1, 4, 50] // make multiple requests. } @@ -259,82 +250,68 @@ abstract class HttpServerTest extends InstrumentationSpecification imple setup: def traceId = "00000000000000000000000000000123" def parentId = "0000000000000456" - def request = request(SUCCESS, method, body) - .header("traceparent", "00-" + traceId.toString() + "-" + parentId.toString() + "-01") - .build() - def response = client.newCall(request).execute() + def request = AggregatedHttpRequest.of( + request(SUCCESS, method).headers().toBuilder() + .set("traceparent", "00-" + traceId.toString() + "-" + parentId.toString() + "-01") + .build()) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == SUCCESS.status - assert response.body().string() == SUCCESS.body - true - } + response.status().code() == SUCCESS.status + response.contentUtf8() == SUCCESS.body and: assertTheTraces(1, traceId, parentId, "GET", SUCCESS, null, response) where: method = "GET" - body = null } def "test tag query string for #endpoint"() { setup: - def request = request(endpoint, method, body).build() - Response response = client.newCall(request).execute() + def request = request(endpoint, method) + AggregatedHttpResponse response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == endpoint.status - assert response.body().string() == endpoint.body - true - } + response.status().code() == endpoint.status + response.contentUtf8() == endpoint.body and: assertTheTraces(1, null, null, method, endpoint, null, response) where: method = "GET" - body = null endpoint << [SUCCESS, QUERY_PARAM] } def "test redirect"() { setup: assumeTrue(testRedirect()) - def request = request(REDIRECT, method, body).build() - def response = client.newCall(request).execute() + def request = request(REDIRECT, method) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == REDIRECT.status - assert response.header("location") == REDIRECT.body || - new URI(response.header("location")).normalize().toString() == "${address.resolve(REDIRECT.body)}" - true - } + response.status().code() == REDIRECT.status + response.headers().get("location") == REDIRECT.body || + new URI(response.headers().get("location")).normalize().toString() == "${address.resolve(REDIRECT.body)}" and: assertTheTraces(1, null, null, method, REDIRECT, null, response) where: method = "GET" - body = null } def "test error"() { setup: assumeTrue(testError()) - def request = request(ERROR, method, body).build() - def response = client.newCall(request).execute() + def request = request(ERROR, method) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == ERROR.status - if (testErrorBody()) { - assert response.body().string() == ERROR.body - } - true + response.status().code() == ERROR.status + if (testErrorBody()) { + response.contentUtf8() == ERROR.body } and: @@ -342,68 +319,55 @@ abstract class HttpServerTest extends InstrumentationSpecification imple where: method = "GET" - body = null } def "test exception"() { setup: assumeTrue(testException()) - def request = request(EXCEPTION, method, body).build() - def response = client.newCall(request).execute() + def request = request(EXCEPTION, method) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == EXCEPTION.status - true - } + response.status().code() == EXCEPTION.status and: assertTheTraces(1, null, null, method, EXCEPTION, EXCEPTION.body, response) where: method = "GET" - body = null } def "test notFound"() { setup: assumeTrue(testNotFound()) - def request = request(NOT_FOUND, method, body).build() - def response = client.newCall(request).execute() + def request = request(NOT_FOUND, method) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == NOT_FOUND.status - true - } + response.status().code() == NOT_FOUND.status and: assertTheTraces(1, null, null, method, NOT_FOUND, null, response) where: method = "GET" - body = null } def "test path param"() { setup: assumeTrue(testPathParam()) - def request = request(PATH_PARAM, method, body).build() - def response = client.newCall(request).execute() + def request = request(PATH_PARAM, method) + def response = client.execute(request).aggregate().join() expect: - response.withCloseable { - assert response.code() == PATH_PARAM.status - assert response.body().string() == PATH_PARAM.body - true - } + response.status().code() == PATH_PARAM.status + response.contentUtf8() == PATH_PARAM.body and: assertTheTraces(1, null, null, method, PATH_PARAM, null, response) where: method = "GET" - body = null } /* @@ -430,7 +394,7 @@ abstract class HttpServerTest extends InstrumentationSpecification imple def pool = Executors.newFixedThreadPool(4) def propagator = GlobalOpenTelemetry.getPropagators().getTextMapPropagator() - def setter = { Request.Builder carrier, String name, String value -> + def setter = { HttpRequestBuilder carrier, String name, String value -> carrier.header(name, value) } @@ -438,14 +402,14 @@ abstract class HttpServerTest extends InstrumentationSpecification imple count.times { index -> def job = { latch.await() - def url = HttpUrl.get(endpoint.resolvePath(address)).newBuilder() - .query("${ServerEndpoint.ID_PARAMETER_NAME}=$index") - .build() - Request.Builder builder = request(url, "GET", null) + HttpRequestBuilder request = HttpRequest.builder() + // Force HTTP/1 via h1c so upgrade requests don't show up as traces + .get(endpoint.resolvePath(address).toString().replace("http://", "h1c://")) + .queryParam(ServerEndpoint.ID_PARAMETER_NAME, "$index") runUnderTrace("client " + index) { Span.current().setAttribute(ServerEndpoint.ID_ATTRIBUTE_NAME, index) - propagator.inject(Context.current(), builder, setter) - client.newCall(builder.build()).execute() + propagator.inject(Context.current(), request, setter) + client.execute(request.build()).aggregate().join() } } @@ -485,7 +449,7 @@ abstract class HttpServerTest extends InstrumentationSpecification imple //FIXME: add tests for POST with large/chunked data - void assertTheTraces(int size, String traceID = null, String parentID = null, String method = "GET", ServerEndpoint endpoint = SUCCESS, String errorMessage = null, Response response = null) { + void assertTheTraces(int size, String traceID = null, String parentID = null, String method = "GET", ServerEndpoint endpoint = SUCCESS, String errorMessage = null, AggregatedHttpResponse response = null) { def spanCount = 1 // server span if (hasResponseSpan(endpoint)) { spanCount++ @@ -506,7 +470,7 @@ abstract class HttpServerTest extends InstrumentationSpecification imple (0..size - 1).each { trace(it, spanCount) { def spanIndex = 0 - serverSpan(it, spanIndex++, traceID, parentID, method, response?.body()?.contentLength(), endpoint) + serverSpan(it, spanIndex++, traceID, parentID, method, response?.content()?.length(), endpoint) if (hasHandlerSpan(endpoint)) { handlerSpan(it, spanIndex++, span(0), method, endpoint) } @@ -611,7 +575,7 @@ abstract class HttpServerTest extends InstrumentationSpecification imple "${SemanticAttributes.HTTP_URL.key}" { it == "${endpoint.resolve(address)}" || it == "${endpoint.resolveWithoutFragment(address)}" } "${SemanticAttributes.HTTP_METHOD.key}" method "${SemanticAttributes.HTTP_STATUS_CODE.key}" endpoint.status - "${SemanticAttributes.HTTP_FLAVOR.key}" "1.1" + "${SemanticAttributes.HTTP_FLAVOR.key}" { it == "1.1" || it == "2.0" } "${SemanticAttributes.HTTP_USER_AGENT.key}" TEST_USER_AGENT if (extraAttributes.contains(SemanticAttributes.HTTP_HOST)) { @@ -675,6 +639,4 @@ abstract class HttpServerTest extends InstrumentationSpecification imple } } } - - } diff --git a/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTestTrait.groovy b/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTestTrait.groovy index de9fe08fff..94fb627597 100644 --- a/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTestTrait.groovy +++ b/testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpServerTestTrait.groovy @@ -8,14 +8,16 @@ package io.opentelemetry.instrumentation.test.base import ch.qos.logback.classic.Level import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait import io.opentelemetry.instrumentation.test.utils.LoggerUtils -import io.opentelemetry.instrumentation.test.utils.OkHttpUtils import io.opentelemetry.instrumentation.test.utils.PortUtils -import okhttp3.OkHttpClient +import io.opentelemetry.testing.armeria.client.ClientFactory +import io.opentelemetry.testing.armeria.client.WebClient +import io.opentelemetry.testing.armeria.client.logging.LoggingClient +import io.opentelemetry.testing.armeria.common.HttpHeaderNames +import java.time.Duration import org.junit.AfterClass import org.junit.BeforeClass import org.slf4j.Logger import org.slf4j.LoggerFactory - /** * A trait for testing requests against http server. */ @@ -29,7 +31,14 @@ trait HttpServerTestTrait implements RetryOnAddressAlreadyInUseTrait { // not using SERVER as type because it triggers a bug in groovy and java joint compilation static Object server - static OkHttpClient client = OkHttpUtils.client() + static WebClient client = WebClient.builder() + .responseTimeout(Duration.ofMinutes(1)) + .writeTimeout(Duration.ofMinutes(1)) + .factory(ClientFactory.builder().connectTimeout(Duration.ofMinutes(1)).build()) + .setHeader(HttpHeaderNames.USER_AGENT, TEST_USER_AGENT) + .setHeader(HttpHeaderNames.X_FORWARDED_FOR, TEST_CLIENT_IP) + .decorator(LoggingClient.newDecorator()) + .build() static int port static URI address