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 <trask.stalnaker@gmail.com>

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Anuraag Agrawal 2021-06-11 08:56:02 +09:00 committed by GitHub
parent d79fb8cc84
commit 60aaff8972
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 256 additions and 388 deletions

View File

@ -9,13 +9,9 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils
import io.opentelemetry.instrumentation.test.utils.PortUtils import io.opentelemetry.instrumentation.test.utils.PortUtils
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import okhttp3.FormBody import io.opentelemetry.testing.armeria.client.WebClient
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.springframework.boot.SpringApplication import org.springframework.boot.SpringApplication
import org.springframework.context.ConfigurableApplicationContext import org.springframework.context.ConfigurableApplicationContext
import spock.lang.Shared import spock.lang.Shared
@ -25,7 +21,7 @@ class SingleServiceCamelTest extends AgentInstrumentationSpecification implement
@Shared @Shared
ConfigurableApplicationContext server ConfigurableApplicationContext server
@Shared @Shared
OkHttpClient client = OkHttpUtils.client() WebClient client = WebClient.of()
@Shared @Shared
int port int port
@Shared @Shared
@ -56,15 +52,9 @@ class SingleServiceCamelTest extends AgentInstrumentationSpecification implement
def "single camel service span"() { def "single camel service span"() {
setup: setup:
def requestUrl = address.resolve("/camelService") 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: when:
client.newCall(request).execute() client.post(requestUrl.toString(), "testContent").aggregate().join()
then: then:
assertTraces(1) { assertTraces(1) {

View File

@ -6,11 +6,8 @@
import static io.opentelemetry.api.trace.SpanKind.SERVER import static io.opentelemetry.api.trace.SpanKind.SERVER
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils import io.opentelemetry.testing.armeria.client.WebClient
import okhttp3.HttpUrl import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jboss.arquillian.container.test.api.Deployment import org.jboss.arquillian.container.test.api.Deployment
import org.jboss.arquillian.container.test.api.RunAsClient import org.jboss.arquillian.container.test.api.RunAsClient
import org.jboss.arquillian.spock.ArquillianSputnik import org.jboss.arquillian.spock.ArquillianSputnik
@ -28,7 +25,7 @@ import test.RestApplication
@RunAsClient @RunAsClient
abstract class ArquillianRestTest extends AgentInstrumentationSpecification { abstract class ArquillianRestTest extends AgentInstrumentationSpecification {
static OkHttpClient client = OkHttpUtils.client() static WebClient client = WebClient.of()
@ArquillianResource @ArquillianResource
static URI url static URI url
@ -49,15 +46,11 @@ abstract class ArquillianRestTest extends AgentInstrumentationSpecification {
@Unroll @Unroll
def "test #path"() { def "test #path"() {
when: when:
Request request = new Request.Builder().url(HttpUrl.get(url.resolve(path))).build() AggregatedHttpResponse response = client.get(url.resolve(path).toString()).aggregate().join()
Response response = client.newCall(request).execute()
then: then:
response.withCloseable { response.status().code() == 200
assert response.code() == 200 response.contentUtf8() == "hello"
assert response.body().string() == "hello"
true
}
and: and:
assertTraces(1) { assertTraces(1) {

View File

@ -8,11 +8,10 @@ import static Resource.Test2
import static Resource.Test3 import static Resource.Test3
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait
import okhttp3.FormBody import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response
import org.apache.cxf.endpoint.Server import org.apache.cxf.endpoint.Server
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean import org.apache.cxf.jaxrs.JAXRSServerFactoryBean
@ -54,10 +53,8 @@ class CxfFilterTest extends JaxRsFilterTest implements HttpServerTestTrait<Serve
@Override @Override
def makeRequest(String path) { def makeRequest(String path) {
def url = HttpUrl.get(address.resolve(path)).newBuilder().build() AggregatedHttpResponse response = client.post(address.resolve(path).toString(), "").aggregate().join()
def request = request(url, "POST", new FormBody.Builder().build()).build()
Response response = client.newCall(request).execute()
return [response.body().string(), response.code()] return [response.contentUtf8(), response.status().code()]
} }
} }

View File

@ -18,12 +18,6 @@ import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CompletableFuture
import okhttp3.Call
import okhttp3.Callback
import okhttp3.HttpUrl
import okhttp3.Request
import okhttp3.Response
import spock.lang.Unroll import spock.lang.Unroll
import test.JaxRsTestResource import test.JaxRsTestResource
@ -31,17 +25,11 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
def "test super method without @Path"() { def "test super method without @Path"() {
given: given:
def url = HttpUrl.get(address.resolve("test-resource-super")).newBuilder() def response = client.get(address.resolve("test-resource-super").toString()).aggregate().join()
.build()
def request = request(url, "GET", null).build()
def response = client.newCall(request).execute()
expect: expect:
response.withCloseable { response.status().code() == SUCCESS.status
assert response.code() == SUCCESS.status response.contentUtf8() == SUCCESS.body
assert response.body().string() == SUCCESS.body
true
}
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 2) {
@ -59,17 +47,11 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
assumeTrue(testInterfaceMethodWithPath()) assumeTrue(testInterfaceMethodWithPath())
given: given:
def url = HttpUrl.get(address.resolve("test-resource-interface/call")).newBuilder() def response = client.get(address.resolve("test-resource-interface/call").toString()).aggregate().join()
.build()
def request = request(url, "GET", null).build()
def response = client.newCall(request).execute()
expect: expect:
response.withCloseable { response.status().code() == SUCCESS.status
assert response.code() == SUCCESS.status response.contentUtf8() == SUCCESS.body
assert response.body().string() == SUCCESS.body
true
}
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 2) {
@ -85,17 +67,11 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
def "test sub resource locator"() { def "test sub resource locator"() {
given: given:
def url = HttpUrl.get(address.resolve("test-sub-resource-locator/call/sub")).newBuilder() def response = client.get(address.resolve("test-sub-resource-locator/call/sub").toString()).aggregate().join()
.build()
def request = request(url, "GET", null).build()
def response = client.newCall(request).execute()
expect: expect:
response.withCloseable { response.status().code() == SUCCESS.status
assert response.code() == SUCCESS.status response.contentUtf8() == SUCCESS.body
assert response.body().string() == SUCCESS.body
true
}
assertTraces(1) { assertTraces(1) {
trace(0, 5) { trace(0, 5) {
@ -115,13 +91,10 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
@Unroll @Unroll
def "should handle #desc AsyncResponse"() { def "should handle #desc AsyncResponse"() {
given: given:
def url = HttpUrl.get(address.resolve("async")).newBuilder() def url = address.resolve("async?action=${action}").toString()
.addQueryParameter("action", action)
.build()
def request = request(url, "GET", null).build()
when: "async call is started" when: "async call is started"
def futureResponse = asyncCall(request) def futureResponse = client.get(url).aggregate()
then: "there are no traces yet" then: "there are no traces yet"
assertTraces(0) { assertTraces(0) {
@ -132,8 +105,8 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
def response = futureResponse.join() def response = futureResponse.join()
then: then:
assert response.code() == statusCode response.status().code() == statusCode
assert bodyPredicate(response.body().string()) bodyPredicate(response.contentUtf8())
def spanCount = 2 def spanCount = 2
def hasSendError = asyncCancelHasSendError() && action == "cancel" def hasSendError = asyncCancelHasSendError() && action == "cancel"
@ -160,15 +133,11 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
@Unroll @Unroll
def "should handle #desc CompletionStage (JAX-RS 2.1+ only)"() { def "should handle #desc CompletionStage (JAX-RS 2.1+ only)"() {
assumeTrue(shouldTestCompletableStageAsync()) assumeTrue(shouldTestCompletableStageAsync())
given: given:
def url = HttpUrl.get(address.resolve("async-completion-stage")).newBuilder() def url = address.resolve("async-completion-stage?action=${action}").toString()
.addQueryParameter("action", action)
.build()
def request = request(url, "GET", null).build()
when: "async call is started" when: "async call is started"
def futureResponse = asyncCall(request) def futureResponse = client.get(url).aggregate()
then: "there are no traces yet" then: "there are no traces yet"
assertTraces(0) { assertTraces(0) {
@ -179,8 +148,8 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
def response = futureResponse.join() def response = futureResponse.join()
then: then:
assert response.code() == statusCode response.status().code() == statusCode
assert bodyPredicate(response.body().string()) bodyPredicate(response.contentUtf8())
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 2) {
@ -245,9 +214,9 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
void asyncServerSpan(TraceAssert trace, void asyncServerSpan(TraceAssert trace,
int index, int index,
HttpUrl url, String url,
int statusCode) { int statusCode) {
def rawUrl = url.url() def rawUrl = URI.create(url).toURL()
serverSpan(trace, index, null, null, "GET", serverSpan(trace, index, null, null, "GET",
rawUrl.path, rawUrl.path,
rawUrl.toURI(), rawUrl.toURI(),
@ -328,22 +297,4 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
} }
} }
} }
private CompletableFuture<Response> 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
}
} }

View File

@ -11,11 +11,13 @@ import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import okhttp3.FormBody import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest
import okhttp3.HttpUrl import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import okhttp3.Request import io.opentelemetry.testing.armeria.common.HttpData
import okhttp3.RequestBody import io.opentelemetry.testing.armeria.common.HttpMethod
import okhttp3.Response 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.annotations.AnnotationConfiguration
import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.Server
import org.eclipse.jetty.util.resource.Resource import org.eclipse.jetty.util.resource.Resource
@ -72,13 +74,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
@Unroll @Unroll
def "test #path"() { def "test #path"() {
setup: setup:
def url = HttpUrl.get(address.resolve("hello.jsf")).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve("hello.jsf").toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == 200 response.status().code() == 200
response.body().string().trim() == "Hello" response.contentUtf8().trim() == "Hello"
and: and:
assertTraces(1) { assertTraces(1) {
@ -94,13 +94,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
def "test greeting"() { def "test greeting"() {
// we need to display the page first before posting data to it // we need to display the page first before posting data to it
setup: setup:
def url = HttpUrl.get(address.resolve("greeting.jsf")).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve("greeting.jsf").toString()).aggregate().join()
def request = request(url, "GET", null).build() def doc = Jsoup.parse(response.contentUtf8())
Response response = client.newCall(request).execute()
def doc = Jsoup.parse(response.body().string())
expect: expect:
response.code() == 200 response.status().code() == 200
doc.selectFirst("title").text() == "Hello, World!" doc.selectFirst("title").text() == "Hello, World!"
and: and:
@ -122,10 +120,8 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
jsessionid != null jsessionid != null
when: 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 // set up form parameter for post
RequestBody formBody = new FormBody.Builder() QueryParams formBody = QueryParams.builder()
.add("app-form", "app-form") .add("app-form", "app-form")
// value used for name is returned in app-form:output-message element // value used for name is returned in app-form:output-message element
.add("app-form:name", "test") .add("app-form:name", "test")
@ -133,13 +129,18 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
.add("app-form_SUBMIT", "1") // MyFaces .add("app-form_SUBMIT", "1") // MyFaces
.add("javax.faces.ViewState", viewState) .add("javax.faces.ViewState", viewState)
.build() .build()
def request2 = this.request(url2, "POST", formBody).build() // use the session created for first request
Response response2 = client.newCall(request2).execute() def request2 = AggregatedHttpRequest.of(
def responseContent = response2.body().string() 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) def doc2 = Jsoup.parse(responseContent)
then: then:
response2.code() == 200 response2.status().code() == 200
doc2.getElementById("app-form:output-message").text() == "Hello test" doc2.getElementById("app-form:output-message").text() == "Hello test"
and: and:
@ -154,13 +155,11 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
def "test exception"() { def "test exception"() {
// we need to display the page first before posting data to it // we need to display the page first before posting data to it
setup: setup:
def url = HttpUrl.get(address.resolve("greeting.jsf")).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve("greeting.jsf").toString()).aggregate().join()
def request = request(url, "GET", null).build() def doc = Jsoup.parse(response.contentUtf8())
Response response = client.newCall(request).execute()
def doc = Jsoup.parse(response.body().string())
expect: expect:
response.code() == 200 response.status().code() == 200
doc.selectFirst("title").text() == "Hello, World!" doc.selectFirst("title").text() == "Hello, World!"
and: and:
@ -182,10 +181,8 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
jsessionid != null jsessionid != null
when: 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 // set up form parameter for post
RequestBody formBody = new FormBody.Builder() QueryParams formBody = QueryParams.builder()
.add("app-form", "app-form") .add("app-form", "app-form")
// setting name parameter to "exception" triggers throwing exception in GreetingForm // setting name parameter to "exception" triggers throwing exception in GreetingForm
.add("app-form:name", "exception") .add("app-form:name", "exception")
@ -193,11 +190,16 @@ abstract class BaseJsfTest extends AgentInstrumentationSpecification implements
.add("app-form_SUBMIT", "1") // MyFaces .add("app-form_SUBMIT", "1") // MyFaces
.add("javax.faces.ViewState", viewState) .add("javax.faces.ViewState", viewState)
.build() .build()
def request2 = this.request(url2, "POST", formBody).build() // use the session created for first request
Response response2 = client.newCall(request2).execute() 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: then:
response2.code() == 500 response2.status().code() == 500
and: and:
assertTraces(1) { 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) { void handlerSpan(TraceAssert trace, int index, Object parent, String spanName, Exception expectedException = null) {
trace.span(index) { trace.span(index) {
name spanName name spanName

View File

@ -74,8 +74,10 @@ class Netty38ServerTest extends HttpServerTest<ServerBootstrap> implements Agent
response.setContent(responseContent) response.setContent(responseContent)
break break
case INDEXED_CHILD: case INDEXED_CHILD:
responseContent = ChannelBuffers.EMPTY_BUFFER
endpoint.collectSpanAttributes { new QueryStringDecoder(uri).getParameters().get(it).find() } endpoint.collectSpanAttributes { new QueryStringDecoder(uri).getParameters().get(it).find() }
response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status))
response.setContent(responseContent)
break break
case QUERY_PARAM: case QUERY_PARAM:
responseContent = ChannelBuffers.copiedBuffer(uri.query, CharsetUtil.UTF_8) responseContent = ChannelBuffers.copiedBuffer(uri.query, CharsetUtil.UTF_8)
@ -83,7 +85,9 @@ class Netty38ServerTest extends HttpServerTest<ServerBootstrap> implements Agent
response.setContent(responseContent) response.setContent(responseContent)
break break
case REDIRECT: case REDIRECT:
responseContent = ChannelBuffers.EMPTY_BUFFER
response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status)) response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status))
response.setContent(responseContent)
response.headers().set(LOCATION, endpoint.body) response.headers().set(LOCATION, endpoint.body)
break break
case EXCEPTION: case EXCEPTION:

View File

@ -72,15 +72,17 @@ class Netty40ServerTest extends HttpServerTest<EventLoopGroup> implements AgentT
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
break break
case INDEXED_CHILD: case INDEXED_CHILD:
content = Unpooled.EMPTY_BUFFER
endpoint.collectSpanAttributes { new QueryStringDecoder(uri).parameters().get(it).find() } 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 break
case QUERY_PARAM: case QUERY_PARAM:
content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8) content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8)
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
break break
case REDIRECT: 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) response.headers().set(HttpHeaders.Names.LOCATION, endpoint.body)
break break
case EXCEPTION: case EXCEPTION:

View File

@ -71,15 +71,17 @@ class Netty41ServerTest extends HttpServerTest<EventLoopGroup> implements AgentT
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
break break
case INDEXED_CHILD: case INDEXED_CHILD:
content = Unpooled.EMPTY_BUFFER
endpoint.collectSpanAttributes { new QueryStringDecoder(uri).parameters().get(it).find() } 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 break
case QUERY_PARAM: case QUERY_PARAM:
content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8) content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8)
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content) response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
break break
case REDIRECT: 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) response.headers().set(HttpHeaderNames.LOCATION, endpoint.body)
break break
case EXCEPTION: case EXCEPTION:

View File

@ -7,66 +7,65 @@ import static io.opentelemetry.api.trace.SpanKind.INTERNAL
import static io.opentelemetry.api.trace.SpanKind.SERVER import static io.opentelemetry.api.trace.SpanKind.SERVER
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import okhttp3.HttpUrl import io.opentelemetry.testing.armeria.client.WebClient
import okhttp3.OkHttpClient
import okhttp3.Request
import ratpack.path.PathBinding import ratpack.path.PathBinding
import ratpack.server.RatpackServer import ratpack.server.RatpackServer
import spock.lang.Shared
class RatpackOtherTest extends AgentInstrumentationSpecification { class RatpackOtherTest extends AgentInstrumentationSpecification {
OkHttpClient client = OkHttpUtils.client() @Shared
RatpackServer app = RatpackServer.start {
def "test bindings for #path"() { it.handlers {
setup: it.prefix("a") {
def app = RatpackServer.start { it.all {context ->
it.handlers { context.render(context.get(PathBinding).description)
it.prefix("a") {
it.all {context ->
context.render(context.get(PathBinding).description)
}
} }
it.prefix("b/::\\d+") { }
it.all {context -> it.prefix("b/::\\d+") {
context.render(context.get(PathBinding).description) it.all {context ->
} context.render(context.get(PathBinding).description)
} }
it.prefix("c/:val?") { }
it.all {context -> it.prefix("c/:val?") {
context.render(context.get(PathBinding).description) it.all {context ->
} context.render(context.get(PathBinding).description)
} }
it.prefix("d/:val") { }
it.all {context -> it.prefix("d/:val") {
context.render(context.get(PathBinding).description) it.all {context ->
} context.render(context.get(PathBinding).description)
} }
it.prefix("e/:val?:\\d+") { }
it.all {context -> it.prefix("e/:val?:\\d+") {
context.render(context.get(PathBinding).description) it.all {context ->
} context.render(context.get(PathBinding).description)
} }
it.prefix("f/:val:\\d+") { }
it.all {context -> it.prefix("f/:val:\\d+") {
context.render(context.get(PathBinding).description) 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: when:
def resp = client.newCall(request).execute() def resp = client.get(path).aggregate().join()
then: then:
resp.code() == 200 resp.status().code() == 200
resp.body.string() == route resp.contentUtf8() == route
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 2) {
@ -77,7 +76,7 @@ class RatpackOtherTest extends AgentInstrumentationSpecification {
attributes { attributes {
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"
"${SemanticAttributes.NET_PEER_PORT.key}" Long "${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_METHOD.key}" "GET"
"${SemanticAttributes.HTTP_STATUS_CODE.key}" 200 "${SemanticAttributes.HTTP_STATUS_CODE.key}" 200
"${SemanticAttributes.HTTP_FLAVOR.key}" "1.1" "${SemanticAttributes.HTTP_FLAVOR.key}" "1.1"
@ -95,9 +94,6 @@ class RatpackOtherTest extends AgentInstrumentationSpecification {
} }
} }
cleanup:
app.stop()
where: where:
path | route path | route
"a" | "a" "a" | "a"

View File

@ -8,6 +8,7 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import javax.servlet.Servlet import javax.servlet.Servlet
import javax.servlet.ServletException import javax.servlet.ServletException
import javax.servlet.http.HttpServlet import javax.servlet.http.HttpServlet
@ -16,7 +17,6 @@ import javax.servlet.http.HttpServletResponse
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response
import spock.lang.Unroll import spock.lang.Unroll
abstract class AbstractServlet3MappingTest<SERVER, CONTEXT> extends AgentInstrumentationSpecification implements HttpServerTestTrait<SERVER> { abstract class AbstractServlet3MappingTest<SERVER, CONTEXT> extends AgentInstrumentationSpecification implements HttpServerTestTrait<SERVER> {
@ -44,12 +44,10 @@ abstract class AbstractServlet3MappingTest<SERVER, CONTEXT> extends AgentInstrum
@Unroll @Unroll
def "test path #path"() { def "test path #path"() {
setup: setup:
def url = HttpUrl.get(address.resolve(path)).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve(path).toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == success ? 200 : 404 response.status().code() == success ? 200 : 404
and: and:
def spanCount = success ? 1 : 2 def spanCount = success ? 1 : 2

View File

@ -14,9 +14,8 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest
import javax.servlet.Servlet import javax.servlet.Servlet
import okhttp3.Request
import okhttp3.RequestBody
abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERVER> implements AgentTestTrait { abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERVER> implements AgentTestTrait {
@Override @Override
@ -49,9 +48,9 @@ abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERV
protected ServerEndpoint lastRequest protected ServerEndpoint lastRequest
@Override @Override
Request.Builder request(ServerEndpoint uri, String method, RequestBody body) { AggregatedHttpRequest request(ServerEndpoint uri, String method) {
lastRequest = uri lastRequest = uri
super.request(uri, method, body) super.request(uri, method)
} }
boolean errorEndpointUsesSendError() { boolean errorEndpointUsesSendError() {

View File

@ -13,6 +13,7 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn
import static org.junit.Assume.assumeTrue import static org.junit.Assume.assumeTrue
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import java.nio.file.Files import java.nio.file.Files
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
@ -117,17 +118,17 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
def "access log has ids for #count requests"() { def "access log has ids for #count requests"() {
given: given:
def request = request(SUCCESS, method, body).build() def request = request(SUCCESS, method)
when: when:
List<okhttp3.Response> responses = (1..count).collect { List<AggregatedHttpResponse> responses = (1..count).collect {
return client.newCall(request).execute() return client.execute(request).aggregate().join()
} }
then: then:
responses.each { response -> responses.each { response ->
assert response.code() == SUCCESS.status assert response.status().code() == SUCCESS.status
assert response.body().string() == SUCCESS.body assert response.contentUtf8() == SUCCESS.body
} }
and: and:
@ -150,19 +151,18 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
where: where:
method = "GET" method = "GET"
body = null
count << [1, 4] // make multiple requests. count << [1, 4] // make multiple requests.
} }
def "access log has ids for error request"() { def "access log has ids for error request"() {
setup: setup:
assumeTrue(testError()) assumeTrue(testError())
def request = request(ERROR, method, body).build() def request = request(ERROR, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.code() == ERROR.status response.status().code() == ERROR.status
response.body().string() == ERROR.body response.contentUtf8() == ERROR.body
and: and:
def spanCount = 2 def spanCount = 2
@ -171,7 +171,7 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
} }
assertTraces(1) { assertTraces(1) {
trace(0, spanCount) { 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 def spanIndex = 1
controllerSpan(it, spanIndex, span(spanIndex - 1)) controllerSpan(it, spanIndex, span(spanIndex - 1))
spanIndex++ spanIndex++
@ -189,7 +189,6 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
where: where:
method = "GET" method = "GET"
body = null
} }
// FIXME: Add authentication tests back in... // FIXME: Add authentication tests back in...

View File

@ -8,6 +8,7 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import jakarta.servlet.Servlet import jakarta.servlet.Servlet
import jakarta.servlet.ServletException import jakarta.servlet.ServletException
import jakarta.servlet.http.HttpServlet import jakarta.servlet.http.HttpServlet
@ -16,7 +17,6 @@ import jakarta.servlet.http.HttpServletResponse
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response
import spock.lang.Unroll import spock.lang.Unroll
abstract class AbstractServlet5MappingTest<SERVER, CONTEXT> extends AgentInstrumentationSpecification implements HttpServerTestTrait<SERVER> { abstract class AbstractServlet5MappingTest<SERVER, CONTEXT> extends AgentInstrumentationSpecification implements HttpServerTestTrait<SERVER> {
@ -44,12 +44,10 @@ abstract class AbstractServlet5MappingTest<SERVER, CONTEXT> extends AgentInstrum
@Unroll @Unroll
def "test path #path"() { def "test path #path"() {
setup: setup:
def url = HttpUrl.get(address.resolve(path)).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve(path).toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == success ? 200 : 404 response.status().code() == (success ? 200 : 404)
and: and:
def spanCount = success ? 1 : 2 def spanCount = success ? 1 : 2

View File

@ -14,9 +14,8 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest
import jakarta.servlet.Servlet import jakarta.servlet.Servlet
import okhttp3.Request
import okhttp3.RequestBody
abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERVER> implements AgentTestTrait { abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERVER> implements AgentTestTrait {
@Override @Override
@ -49,9 +48,9 @@ abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERV
protected ServerEndpoint lastRequest protected ServerEndpoint lastRequest
@Override @Override
Request.Builder request(ServerEndpoint uri, String method, RequestBody body) { AggregatedHttpRequest request(ServerEndpoint uri, String method) {
lastRequest = uri lastRequest = uri
super.request(uri, method, body) super.request(uri, method)
} }
boolean errorEndpointUsesSendError() { boolean errorEndpointUsesSendError() {

View File

@ -13,6 +13,7 @@ import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEn
import static org.junit.Assume.assumeTrue import static org.junit.Assume.assumeTrue
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import jakarta.servlet.Servlet import jakarta.servlet.Servlet
import jakarta.servlet.ServletException import jakarta.servlet.ServletException
import java.nio.file.Files import java.nio.file.Files
@ -117,17 +118,17 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
def "access log has ids for #count requests"() { def "access log has ids for #count requests"() {
given: given:
def request = request(SUCCESS, method, body).build() def request = request(SUCCESS, method)
when: when:
List<okhttp3.Response> responses = (1..count).collect { List<AggregatedHttpResponse> responses = (1..count).collect {
return client.newCall(request).execute() return client.execute(request).aggregate().join()
} }
then: then:
responses.each { response -> responses.each { response ->
assert response.code() == SUCCESS.status assert response.status().code() == SUCCESS.status
assert response.body().string() == SUCCESS.body assert response.contentUtf8() == SUCCESS.body
} }
and: and:
@ -150,19 +151,18 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
where: where:
method = "GET" method = "GET"
body = null
count << [1, 4] // make multiple requests. count << [1, 4] // make multiple requests.
} }
def "access log has ids for error request"() { def "access log has ids for error request"() {
setup: setup:
assumeTrue(testError()) assumeTrue(testError())
def request = request(ERROR, method, body).build() def request = request(ERROR, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.code() == ERROR.status response.status().code() == ERROR.status
response.body().string() == ERROR.body response.contentUtf8() == ERROR.body
and: and:
def spanCount = 2 def spanCount = 2
@ -171,7 +171,7 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
} }
assertTraces(1) { assertTraces(1) {
trace(0, spanCount) { 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 def spanIndex = 1
controllerSpan(it, spanIndex, span(spanIndex - 1)) controllerSpan(it, spanIndex, span(spanIndex - 1))
spanIndex++ spanIndex++
@ -189,7 +189,6 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
where: where:
method = "GET" method = "GET"
body = null
} }
// FIXME: Add authentication tests back in... // FIXME: Add authentication tests back in...

View File

@ -19,8 +19,10 @@ import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.TraceAssert import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import okhttp3.FormBody import io.opentelemetry.testing.armeria.common.AggregatedHttpRequest
import okhttp3.RequestBody 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.boot.SpringApplication
import org.springframework.context.ConfigurableApplicationContext import org.springframework.context.ConfigurableApplicationContext
import org.springframework.web.servlet.view.RedirectView import org.springframework.web.servlet.view.RedirectView
@ -91,14 +93,14 @@ class SpringBootBasedTest extends HttpServerTest<ConfigurableApplicationContext>
def "test spans with auth error"() { def "test spans with auth error"() {
setup: setup:
def authProvider = server.getBean(SavingAuthenticationProvider) def authProvider = server.getBean(SavingAuthenticationProvider)
def request = request(AUTH_ERROR, "GET", null).build() def request = request(AUTH_ERROR, "GET")
when: when:
authProvider.latestAuthentications.clear() authProvider.latestAuthentications.clear()
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
then: then:
response.code() == 401 // not secured response.status().code() == 401 // not secured
and: and:
assertTraces(1) { assertTraces(1) {
@ -114,24 +116,23 @@ class SpringBootBasedTest extends HttpServerTest<ConfigurableApplicationContext>
setup: setup:
def authProvider = server.getBean(SavingAuthenticationProvider) def authProvider = server.getBean(SavingAuthenticationProvider)
RequestBody formBody = new FormBody.Builder() QueryParams form = QueryParams.of("username", "test", "password", testPassword)
.add("username", "test") def request = AggregatedHttpRequest.of(
.add("password", testPassword).build() request(LOGIN, "POST").headers().toBuilder().contentType(MediaType.FORM_DATA).build(),
HttpData.ofUtf8(form.toQueryString()))
def request = request(LOGIN, "POST", formBody).build()
when: when:
authProvider.latestAuthentications.clear() authProvider.latestAuthentications.clear()
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
then: then:
response.code() == 302 // redirect after success response.status().code() == 302 // redirect after success
authProvider.latestAuthentications.get(0).password == testPassword authProvider.latestAuthentications.get(0).password == testPassword
and: and:
assertTraces(1) { assertTraces(1) {
trace(0, 2) { 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)) redirectSpan(it, 1, span(0))
} }
} }

View File

@ -20,7 +20,6 @@ import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import io.opentelemetry.struts.GreetingServlet import io.opentelemetry.struts.GreetingServlet
import javax.servlet.DispatcherType import javax.servlet.DispatcherType
import okhttp3.HttpUrl
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet import org.eclipse.jetty.servlet.DefaultServlet
@ -125,14 +124,11 @@ class Struts2ActionSpanTest extends HttpServerTest<Server> implements AgentTestT
// does not overwrite server span name given by struts instrumentation. // does not overwrite server span name given by struts instrumentation.
def "test dispatch to servlet"() { def "test dispatch to servlet"() {
setup: setup:
def url = HttpUrl.get(address.resolve("dispatch")).newBuilder() def response = client.get(address.resolve("dispatch").toString()).aggregate().join()
.build()
def request = request(url, "GET", null).build()
def response = client.newCall(request).execute()
expect: expect:
response.code() == 200 response.status().code() == 200
response.body().string() == "greeting" response.contentUtf8() == "greeting"
and: and:
assertTraces(1) { assertTraces(1) {

View File

@ -17,13 +17,11 @@ import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpServerTest import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import io.undertow.Handlers import io.undertow.Handlers
import io.undertow.Undertow import io.undertow.Undertow
import io.undertow.util.Headers import io.undertow.util.Headers
import io.undertow.util.StatusCodes import io.undertow.util.StatusCodes
import okhttp3.HttpUrl
import okhttp3.Response
//TODO make test which mixes handlers and servlets //TODO make test which mixes handlers and servlets
class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTrait { class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTrait {
@ -99,13 +97,11 @@ class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTr
def "test send response"() { def "test send response"() {
setup: setup:
def uri = address.resolve("sendResponse") def uri = address.resolve("sendResponse")
def url = HttpUrl.get(uri).newBuilder().build() AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == 200 response.status().code() == 200
response.body().string().trim() == "sendResponse" response.contentUtf8().trim() == "sendResponse"
and: and:
assertTraces(1) { assertTraces(1) {
@ -141,13 +137,11 @@ class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTr
def "test send response with exception"() { def "test send response with exception"() {
setup: setup:
def uri = address.resolve("sendResponseWithException") def uri = address.resolve("sendResponseWithException")
def url = HttpUrl.get(uri).newBuilder().build() AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == 200 response.status().code() == 200
response.body().string().trim() == "sendResponseWithException" response.contentUtf8().trim() == "sendResponseWithException"
and: and:
assertTraces(1) { assertTraces(1) {

View File

@ -8,11 +8,8 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicServer
import hello.HelloApplication import hello.HelloApplication
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait
import io.opentelemetry.testing.armeria.common.AggregatedHttpResponse
import javax.servlet.DispatcherType 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.apache.wicket.protocol.http.WicketFilter
import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet import org.eclipse.jetty.servlet.DefaultServlet
@ -55,13 +52,11 @@ class WicketTest extends AgentInstrumentationSpecification implements HttpServer
def "test hello"() { def "test hello"() {
setup: setup:
def url = HttpUrl.get(address.resolve("wicket-test/")).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve("wicket-test/").toString()).aggregate().join()
def request = request(url, "GET", null).build() def doc = Jsoup.parse(response.contentUtf8())
Response response = client.newCall(request).execute()
def doc = Jsoup.parse(response.body().string())
expect: expect:
response.code() == 200 response.status().code() == 200
doc.selectFirst("#message").text() == "Hello World!" doc.selectFirst("#message").text() == "Hello World!"
assertTraces(1) { assertTraces(1) {
@ -73,12 +68,10 @@ class WicketTest extends AgentInstrumentationSpecification implements HttpServer
def "test exception"() { def "test exception"() {
setup: setup:
def url = HttpUrl.get(address.resolve("wicket-test/exception")).newBuilder().build() AggregatedHttpResponse response = client.get(address.resolve("wicket-test/exception").toString()).aggregate().join()
def request = request(url, "GET", null).build()
Response response = client.newCall(request).execute()
expect: expect:
response.code() == 500 response.status().code() == 500
assertTraces(1) { assertTraces(1) {
trace(0, 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)
}
} }

View File

@ -5,7 +5,6 @@
package io.opentelemetry.instrumentation.test.base 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.ERROR
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.EXCEPTION import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.INDEXED_CHILD 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.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes 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.Callable
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors import java.util.concurrent.Executors
import okhttp3.HttpUrl
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import spock.lang.Unroll import spock.lang.Unroll
@Unroll @Unroll
@ -207,20 +207,14 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
} }
} }
Request.Builder request(ServerEndpoint uri, String method, RequestBody body) { AggregatedHttpRequest request(ServerEndpoint uri, String method) {
def url = HttpUrl.get(uri.resolvePath(address)).newBuilder() def url = uri.resolvePath(address).toString()
.query(uri.query) // Force HTTP/1 via h1c so upgrade requests don't show up as traces
.fragment(uri.fragment) url = url.replace("http://", "h1c://")
.build() if (uri.query != null) {
return request(url, method, body) url += "?${uri.query}"
} }
return AggregatedHttpRequest.of(HttpMethod.valueOf(method), url)
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)
} }
static <T> T controller(ServerEndpoint endpoint, Callable<T> closure) { static <T> T controller(ServerEndpoint endpoint, Callable<T> closure) {
@ -233,17 +227,15 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
def "test success with #count requests"() { def "test success with #count requests"() {
setup: setup:
def request = request(SUCCESS, method, body).build() def request = request(SUCCESS, method)
List<Response> responses = (1..count).collect { List<AggregatedHttpResponse> responses = (1..count).collect {
return client.newCall(request).execute() return client.execute(request).aggregate().join()
} }
expect: expect:
responses.each { response -> responses.each { response ->
response.withCloseable { assert response.status().code() == SUCCESS.status
assert response.code() == SUCCESS.status assert response.contentUtf8() == SUCCESS.body
assert response.body().string() == SUCCESS.body
}
} }
and: and:
@ -251,7 +243,6 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
where: where:
method = "GET" method = "GET"
body = null
count << [1, 4, 50] // make multiple requests. count << [1, 4, 50] // make multiple requests.
} }
@ -259,82 +250,68 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
setup: setup:
def traceId = "00000000000000000000000000000123" def traceId = "00000000000000000000000000000123"
def parentId = "0000000000000456" def parentId = "0000000000000456"
def request = request(SUCCESS, method, body) def request = AggregatedHttpRequest.of(
.header("traceparent", "00-" + traceId.toString() + "-" + parentId.toString() + "-01") request(SUCCESS, method).headers().toBuilder()
.build() .set("traceparent", "00-" + traceId.toString() + "-" + parentId.toString() + "-01")
def response = client.newCall(request).execute() .build())
def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == SUCCESS.status
assert response.code() == SUCCESS.status response.contentUtf8() == SUCCESS.body
assert response.body().string() == SUCCESS.body
true
}
and: and:
assertTheTraces(1, traceId, parentId, "GET", SUCCESS, null, response) assertTheTraces(1, traceId, parentId, "GET", SUCCESS, null, response)
where: where:
method = "GET" method = "GET"
body = null
} }
def "test tag query string for #endpoint"() { def "test tag query string for #endpoint"() {
setup: setup:
def request = request(endpoint, method, body).build() def request = request(endpoint, method)
Response response = client.newCall(request).execute() AggregatedHttpResponse response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == endpoint.status
assert response.code() == endpoint.status response.contentUtf8() == endpoint.body
assert response.body().string() == endpoint.body
true
}
and: and:
assertTheTraces(1, null, null, method, endpoint, null, response) assertTheTraces(1, null, null, method, endpoint, null, response)
where: where:
method = "GET" method = "GET"
body = null
endpoint << [SUCCESS, QUERY_PARAM] endpoint << [SUCCESS, QUERY_PARAM]
} }
def "test redirect"() { def "test redirect"() {
setup: setup:
assumeTrue(testRedirect()) assumeTrue(testRedirect())
def request = request(REDIRECT, method, body).build() def request = request(REDIRECT, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == REDIRECT.status
assert response.code() == REDIRECT.status response.headers().get("location") == REDIRECT.body ||
assert response.header("location") == REDIRECT.body || new URI(response.headers().get("location")).normalize().toString() == "${address.resolve(REDIRECT.body)}"
new URI(response.header("location")).normalize().toString() == "${address.resolve(REDIRECT.body)}"
true
}
and: and:
assertTheTraces(1, null, null, method, REDIRECT, null, response) assertTheTraces(1, null, null, method, REDIRECT, null, response)
where: where:
method = "GET" method = "GET"
body = null
} }
def "test error"() { def "test error"() {
setup: setup:
assumeTrue(testError()) assumeTrue(testError())
def request = request(ERROR, method, body).build() def request = request(ERROR, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == ERROR.status
assert response.code() == ERROR.status if (testErrorBody()) {
if (testErrorBody()) { response.contentUtf8() == ERROR.body
assert response.body().string() == ERROR.body
}
true
} }
and: and:
@ -342,68 +319,55 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
where: where:
method = "GET" method = "GET"
body = null
} }
def "test exception"() { def "test exception"() {
setup: setup:
assumeTrue(testException()) assumeTrue(testException())
def request = request(EXCEPTION, method, body).build() def request = request(EXCEPTION, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == EXCEPTION.status
assert response.code() == EXCEPTION.status
true
}
and: and:
assertTheTraces(1, null, null, method, EXCEPTION, EXCEPTION.body, response) assertTheTraces(1, null, null, method, EXCEPTION, EXCEPTION.body, response)
where: where:
method = "GET" method = "GET"
body = null
} }
def "test notFound"() { def "test notFound"() {
setup: setup:
assumeTrue(testNotFound()) assumeTrue(testNotFound())
def request = request(NOT_FOUND, method, body).build() def request = request(NOT_FOUND, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == NOT_FOUND.status
assert response.code() == NOT_FOUND.status
true
}
and: and:
assertTheTraces(1, null, null, method, NOT_FOUND, null, response) assertTheTraces(1, null, null, method, NOT_FOUND, null, response)
where: where:
method = "GET" method = "GET"
body = null
} }
def "test path param"() { def "test path param"() {
setup: setup:
assumeTrue(testPathParam()) assumeTrue(testPathParam())
def request = request(PATH_PARAM, method, body).build() def request = request(PATH_PARAM, method)
def response = client.newCall(request).execute() def response = client.execute(request).aggregate().join()
expect: expect:
response.withCloseable { response.status().code() == PATH_PARAM.status
assert response.code() == PATH_PARAM.status response.contentUtf8() == PATH_PARAM.body
assert response.body().string() == PATH_PARAM.body
true
}
and: and:
assertTheTraces(1, null, null, method, PATH_PARAM, null, response) assertTheTraces(1, null, null, method, PATH_PARAM, null, response)
where: where:
method = "GET" method = "GET"
body = null
} }
/* /*
@ -430,7 +394,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
def pool = Executors.newFixedThreadPool(4) def pool = Executors.newFixedThreadPool(4)
def propagator = GlobalOpenTelemetry.getPropagators().getTextMapPropagator() 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) carrier.header(name, value)
} }
@ -438,14 +402,14 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
count.times { index -> count.times { index ->
def job = { def job = {
latch.await() latch.await()
def url = HttpUrl.get(endpoint.resolvePath(address)).newBuilder() HttpRequestBuilder request = HttpRequest.builder()
.query("${ServerEndpoint.ID_PARAMETER_NAME}=$index") // Force HTTP/1 via h1c so upgrade requests don't show up as traces
.build() .get(endpoint.resolvePath(address).toString().replace("http://", "h1c://"))
Request.Builder builder = request(url, "GET", null) .queryParam(ServerEndpoint.ID_PARAMETER_NAME, "$index")
runUnderTrace("client " + index) { runUnderTrace("client " + index) {
Span.current().setAttribute(ServerEndpoint.ID_ATTRIBUTE_NAME, index) Span.current().setAttribute(ServerEndpoint.ID_ATTRIBUTE_NAME, index)
propagator.inject(Context.current(), builder, setter) propagator.inject(Context.current(), request, setter)
client.newCall(builder.build()).execute() client.execute(request.build()).aggregate().join()
} }
} }
@ -485,7 +449,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
//FIXME: add tests for POST with large/chunked data //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 def spanCount = 1 // server span
if (hasResponseSpan(endpoint)) { if (hasResponseSpan(endpoint)) {
spanCount++ spanCount++
@ -506,7 +470,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
(0..size - 1).each { (0..size - 1).each {
trace(it, spanCount) { trace(it, spanCount) {
def spanIndex = 0 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)) { if (hasHandlerSpan(endpoint)) {
handlerSpan(it, spanIndex++, span(0), method, endpoint) handlerSpan(it, spanIndex++, span(0), method, endpoint)
} }
@ -611,7 +575,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
"${SemanticAttributes.HTTP_URL.key}" { it == "${endpoint.resolve(address)}" || it == "${endpoint.resolveWithoutFragment(address)}" } "${SemanticAttributes.HTTP_URL.key}" { it == "${endpoint.resolve(address)}" || it == "${endpoint.resolveWithoutFragment(address)}" }
"${SemanticAttributes.HTTP_METHOD.key}" method "${SemanticAttributes.HTTP_METHOD.key}" method
"${SemanticAttributes.HTTP_STATUS_CODE.key}" endpoint.status "${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 "${SemanticAttributes.HTTP_USER_AGENT.key}" TEST_USER_AGENT
if (extraAttributes.contains(SemanticAttributes.HTTP_HOST)) { if (extraAttributes.contains(SemanticAttributes.HTTP_HOST)) {
@ -675,6 +639,4 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
} }
} }
} }
} }

View File

@ -8,14 +8,16 @@ package io.opentelemetry.instrumentation.test.base
import ch.qos.logback.classic.Level import ch.qos.logback.classic.Level
import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait import io.opentelemetry.instrumentation.test.RetryOnAddressAlreadyInUseTrait
import io.opentelemetry.instrumentation.test.utils.LoggerUtils import io.opentelemetry.instrumentation.test.utils.LoggerUtils
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils
import io.opentelemetry.instrumentation.test.utils.PortUtils 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.AfterClass
import org.junit.BeforeClass import org.junit.BeforeClass
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
/** /**
* A trait for testing requests against http server. * A trait for testing requests against http server.
*/ */
@ -29,7 +31,14 @@ trait HttpServerTestTrait<SERVER> implements RetryOnAddressAlreadyInUseTrait {
// not using SERVER as type because it triggers a bug in groovy and java joint compilation // not using SERVER as type because it triggers a bug in groovy and java joint compilation
static Object server 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 int port
static URI address static URI address