Convert HttpClientTest to JUnit (#3652)

* Migrate HttpClientTest to junit to allow both Java or spock tests.

* More

* Update

* Finish

* Cleanup

* Better stack

* Java 15

* Merge

* Fix name

* Cleanup

* ? extends

* Moar
This commit is contained in:
Anuraag Agrawal 2021-07-27 21:55:40 +09:00 committed by GitHub
parent 262feb1730
commit 47be4a16b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 2060 additions and 1208 deletions

View File

@ -15,7 +15,8 @@ import akka.http.javadsl.model.headers.RawHeader
import akka.stream.ActorMaterializer import akka.stream.ActorMaterializer
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import spock.lang.Shared import spock.lang.Shared
@ -46,7 +47,7 @@ class AkkaHttpClientInstrumentationTest extends HttpClientTest<HttpRequest> impl
} }
@Override @Override
void sendRequestWithCallback(HttpRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
Http.get(system).singleRequest(request, materializer).whenComplete {response, throwable -> Http.get(system).singleRequest(request, materializer).whenComplete {response, throwable ->
if (throwable == null) { if (throwable == null) {
response.discardEntityBytes(materializer) response.discardEntityBytes(materializer)

View File

@ -6,6 +6,7 @@
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import org.apache.http.HttpResponse import org.apache.http.HttpResponse
@ -46,7 +47,7 @@ class ApacheHttpAsyncClientTest extends HttpClientTest<HttpUriRequest> implement
} }
@Override @Override
void sendRequestWithCallback(HttpUriRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpUriRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
client.execute(request, new FutureCallback<HttpResponse>() { client.execute(request, new FutureCallback<HttpResponse>() {
@Override @Override
void completed(HttpResponse httpResponse) { void completed(HttpResponse httpResponse) {

View File

@ -6,6 +6,7 @@
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.function.Consumer import java.util.function.Consumer
import org.apache.http.HttpHost import org.apache.http.HttpHost
@ -59,7 +60,7 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
} }
// compilation fails with @Override annotation on this method (groovy quirk?) // compilation fails with @Override annotation on this method (groovy quirk?)
void sendRequestWithCallback(T request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(T request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
try { try {
executeRequestWithCallback(request, uri) { executeRequestWithCallback(request, uri) {
it.entity?.content?.close() // Make sure the connection is closed. it.entity?.content?.close() // Make sure the connection is closed.

View File

@ -6,6 +6,7 @@
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.function.Consumer import java.util.function.Consumer
@ -64,7 +65,7 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
} }
// compilation fails with @Override annotation on this method (groovy quirk?) // compilation fails with @Override annotation on this method (groovy quirk?)
void sendRequestWithCallback(T request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(T request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
try { try {
executeRequestWithCallback(request, uri) { executeRequestWithCallback(request, uri) {
it.close() // Make sure the connection is closed. it.close() // Make sure the connection is closed.

View File

@ -1,17 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.armeria.v1_3
import com.linecorp.armeria.client.WebClientBuilder
import io.opentelemetry.instrumentation.armeria.v1_3.AbstractArmeriaHttpClientTest
import io.opentelemetry.instrumentation.test.AgentTestTrait
class ArmeriaHttpClientTest extends AbstractArmeriaHttpClientTest implements AgentTestTrait {
@Override
WebClientBuilder configureClient(WebClientBuilder clientBuilder) {
return clientBuilder
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.armeria.v1_3;
import com.linecorp.armeria.client.WebClientBuilder;
import io.opentelemetry.instrumentation.armeria.v1_3.AbstractArmeriaHttpClientTest;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
import org.junit.jupiter.api.extension.RegisterExtension;
class ArmeriaHttpClientTest extends AbstractArmeriaHttpClientTest {
@RegisterExtension
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
@Override
protected WebClientBuilder configureClient(WebClientBuilder clientBuilder) {
return clientBuilder;
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.armeria.v1_3
import com.linecorp.armeria.client.WebClientBuilder
import io.opentelemetry.instrumentation.test.LibraryTestTrait
class ArmeriaHttpClientTest extends AbstractArmeriaHttpClientTest implements LibraryTestTrait {
@Override
WebClientBuilder configureClient(WebClientBuilder clientBuilder) {
return clientBuilder.decorator(ArmeriaTracing.create(getOpenTelemetry()).newClientDecorator())
}
// library instrumentation doesn't have a good way of suppressing nested CLIENT spans yet
@Override
boolean testWithClientParent() {
false
}
// Agent users have automatic propagation through executor instrumentation, but library users
// should do manually using Armeria patterns.
@Override
boolean testCallbackWithParent() {
false
}
@Override
boolean testErrorWithCallback() {
return false
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.armeria.v1_3;
import com.linecorp.armeria.client.WebClientBuilder;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
import org.junit.jupiter.api.extension.RegisterExtension;
class ArmeriaHttpClientTest extends AbstractArmeriaHttpClientTest {
@RegisterExtension
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forLibrary();
@Override
protected WebClientBuilder configureClient(WebClientBuilder clientBuilder) {
return clientBuilder.decorator(
ArmeriaTracing.create(testing.getOpenTelemetry()).newClientDecorator());
}
// library instrumentation doesn't have a good way of suppressing nested CLIENT spans yet
@Override
protected boolean testWithClientParent() {
return false;
}
// Agent users have automatic propagation through executor instrumentation, but library users
// should do manually using Armeria patterns.
@Override
protected boolean testCallbackWithParent() {
return false;
}
@Override
protected boolean testErrorWithCallback() {
return false;
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.armeria.v1_3
import com.linecorp.armeria.client.WebClient
import com.linecorp.armeria.client.WebClientBuilder
import com.linecorp.armeria.common.HttpMethod
import com.linecorp.armeria.common.HttpRequest
import com.linecorp.armeria.common.RequestHeaders
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CompletionException
import spock.lang.Shared
abstract class AbstractArmeriaHttpClientTest extends HttpClientTest<HttpRequest> {
abstract WebClientBuilder configureClient(WebClientBuilder clientBuilder)
@Shared
def client = configureClient(WebClient.builder()).build()
@Override
HttpRequest buildRequest(String method, URI uri, Map<String, String> headers) {
return HttpRequest.of(
RequestHeaders.builder(HttpMethod.valueOf(method), uri.toString())
.set(headers.entrySet())
.build())
}
@Override
int sendRequest(HttpRequest request, String method, URI uri, Map<String, String> headers) {
try {
return client.execute(request)
.aggregate()
.join()
.status()
.code()
} catch (CompletionException e) {
throw e.cause
}
}
@Override
void sendRequestWithCallback(HttpRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) {
client.execute(request).aggregate().whenComplete {response, throwable ->
requestResult.complete({ response.status().code() }, throwable)
}
}
// Not supported yet: https://github.com/line/armeria/issues/2489
@Override
boolean testRedirects() {
false
}
@Override
boolean testReusedRequest() {
// armeria requests can't be reused
false
}
@Override
Set<AttributeKey<?>> httpAttributes(URI uri) {
Set<AttributeKey<?>> extra = [
SemanticAttributes.HTTP_HOST,
SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH,
SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH,
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_TARGET
]
super.httpAttributes(uri) + extra
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.armeria.v1_3;
import com.linecorp.armeria.client.ClientFactory;
import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.client.WebClientBuilder;
import com.linecorp.armeria.common.HttpMethod;
import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.RequestHeaders;
import com.linecorp.armeria.common.util.Exceptions;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.net.URI;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletionException;
import org.junit.jupiter.api.BeforeEach;
public abstract class AbstractArmeriaHttpClientTest extends AbstractHttpClientTest<HttpRequest> {
protected abstract WebClientBuilder configureClient(WebClientBuilder clientBuilder);
private WebClient client;
@BeforeEach
void setupClient() {
client =
configureClient(
WebClient.builder()
.factory(ClientFactory.builder().connectTimeout(connectTimeout()).build()))
.build();
}
@Override
protected final HttpRequest buildRequest(String method, URI uri, Map<String, String> headers) {
return HttpRequest.of(
RequestHeaders.builder(HttpMethod.valueOf(method), uri.toString())
.set(headers.entrySet())
.build());
}
@Override
protected final int sendRequest(
HttpRequest request, String method, URI uri, Map<String, String> headers) {
try {
return client.execute(request).aggregate().join().status().code();
} catch (CompletionException e) {
return Exceptions.throwUnsafely(e.getCause());
}
}
@Override
protected final void sendRequestWithCallback(
HttpRequest request,
String method,
URI uri,
Map<String, String> headers,
RequestResult requestResult) {
client
.execute(request)
.aggregate()
.whenComplete(
(response, throwable) ->
requestResult.complete(() -> response.status().code(), throwable));
}
// Not supported yet: https://github.com/line/armeria/issues/2489
@Override
protected final boolean testRedirects() {
return false;
}
@Override
protected final boolean testReusedRequest() {
// armeria requests can't be reused
return false;
}
@Override
protected Set<AttributeKey<?>> httpAttributes(URI uri) {
Set<AttributeKey<?>> extra = new HashSet<>();
extra.add(SemanticAttributes.HTTP_HOST);
extra.add(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH);
extra.add(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH);
extra.add(SemanticAttributes.HTTP_SCHEME);
extra.add(SemanticAttributes.HTTP_TARGET);
extra.addAll(super.httpAttributes(uri));
return extra;
}
}

View File

@ -12,7 +12,8 @@ import com.ning.http.client.Response
import com.ning.http.client.uri.Uri import com.ning.http.client.uri.Uri
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
@ -39,7 +40,7 @@ class AsyncHttpClientTest extends HttpClientTest<Request> implements AgentTestTr
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
// TODO(anuraaga): Do we also need to test ListenableFuture callback? // TODO(anuraaga): Do we also need to test ListenableFuture callback?
client.executeRequest(request, new AsyncCompletionHandler<Void>() { client.executeRequest(request, new AsyncCompletionHandler<Void>() {
@Override @Override

View File

@ -6,6 +6,7 @@
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.asynchttpclient.AsyncCompletionHandler import org.asynchttpclient.AsyncCompletionHandler
import org.asynchttpclient.Dsl import org.asynchttpclient.Dsl
@ -40,7 +41,7 @@ class AsyncHttpClientTest extends HttpClientTest<Request> implements AgentTestTr
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
client.executeRequest(request, new AsyncCompletionHandler<Void>() { client.executeRequest(request, new AsyncCompletionHandler<Void>() {
@Override @Override
Void onCompleted(Response response) throws Exception { Void onCompleted(Response response) throws Exception {

View File

@ -5,6 +5,7 @@
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import org.springframework.http.HttpEntity import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
@ -44,7 +45,7 @@ class SpringRestTemplateTest extends HttpClientTest<HttpEntity<String>> implemen
} }
@Override @Override
void sendRequestWithCallback(HttpEntity<String> request, String method, URI uri, Map<String, String> headers = [:], RequestResult requestResult) { void sendRequestWithCallback(HttpEntity<String> request, String method, URI uri, Map<String, String> headers = [:], AbstractHttpClientTest.RequestResult requestResult) {
try { try {
restTemplate.execute(uri, HttpMethod.valueOf(method), { req -> restTemplate.execute(uri, HttpMethod.valueOf(method), { req ->
req.getHeaders().putAll(request.getHeaders()) req.getHeaders().putAll(request.getHeaders())

View File

@ -5,6 +5,7 @@
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import java.net.http.HttpClient import java.net.http.HttpClient
import java.net.http.HttpRequest import java.net.http.HttpRequest
import java.net.http.HttpResponse import java.net.http.HttpResponse
@ -38,7 +39,7 @@ class JdkHttpClientTest extends HttpClientTest<HttpRequest> implements AgentTest
} }
@Override @Override
void sendRequestWithCallback(HttpRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.whenComplete { response, throwable -> .whenComplete { response, throwable ->
requestResult.complete({ response.statusCode() }, throwable?.getCause()) requestResult.complete({ response.statusCode() }, throwable?.getCause())

View File

@ -9,7 +9,8 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTr
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.ws.rs.ProcessingException import javax.ws.rs.ProcessingException
@ -46,7 +47,7 @@ abstract class JaxRsClientTest extends HttpClientTest<Invocation.Builder> implem
} }
@Override @Override
void sendRequestWithCallback(Invocation.Builder request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Invocation.Builder request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
def body = BODY_METHODS.contains(method) ? Entity.text("") : null def body = BODY_METHODS.contains(method) ? Entity.text("") : null
request.async().method(method, (Entity) body, new InvocationCallback<Response>() { request.async().method(method, (Entity) body, new InvocationCallback<Response>() {

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException

View File

@ -7,7 +7,9 @@ package io.opentelemetry.instrumentation.jetty.httpclient.v9_2
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.TimeUnit
import org.eclipse.jetty.client.HttpClient import org.eclipse.jetty.client.HttpClient
import org.eclipse.jetty.client.api.ContentResponse import org.eclipse.jetty.client.api.ContentResponse
import org.eclipse.jetty.client.api.Request import org.eclipse.jetty.client.api.Request
@ -15,12 +17,8 @@ import org.eclipse.jetty.client.api.Response
import org.eclipse.jetty.client.api.Result import org.eclipse.jetty.client.api.Result
import org.eclipse.jetty.http.HttpMethod import org.eclipse.jetty.http.HttpMethod
import org.eclipse.jetty.util.ssl.SslContextFactory import org.eclipse.jetty.util.ssl.SslContextFactory
import org.junit.Rule
import org.junit.rules.TestName
import spock.lang.Shared import spock.lang.Shared
import java.util.concurrent.TimeUnit
abstract class AbstractJettyClient9Test extends HttpClientTest<Request> { abstract class AbstractJettyClient9Test extends HttpClientTest<Request> {
abstract HttpClient createStandardClient() abstract HttpClient createStandardClient()
@ -33,9 +31,6 @@ abstract class AbstractJettyClient9Test extends HttpClientTest<Request> {
@Shared @Shared
def httpsClient = null def httpsClient = null
@Rule
TestName name = new TestName()
Request jettyRequest = null Request jettyRequest = null
def setupSpec() { def setupSpec() {
@ -55,6 +50,7 @@ abstract class AbstractJettyClient9Test extends HttpClientTest<Request> {
HttpClient theClient = uri.scheme == 'https' ? httpsClient : client HttpClient theClient = uri.scheme == 'https' ? httpsClient : client
Request request = theClient.newRequest(uri) Request request = theClient.newRequest(uri)
request.agent("Jetty")
HttpMethod methodObj = HttpMethod.valueOf(method) HttpMethod methodObj = HttpMethod.valueOf(method)
request.method(methodObj) request.method(methodObj)
@ -67,9 +63,6 @@ abstract class AbstractJettyClient9Test extends HttpClientTest<Request> {
@Override @Override
String userAgent() { String userAgent() {
if (name.methodName.startsWith('connection error') && jettyRequest.getAgent() == null) {
return null
}
return "Jetty" return "Jetty"
} }
@ -102,7 +95,7 @@ abstract class AbstractJettyClient9Test extends HttpClientTest<Request> {
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
JettyClientListener jcl = new JettyClientListener() JettyClientListener jcl = new JettyClientListener()

View File

@ -11,8 +11,8 @@ import com.ning.http.client.RequestBuilder
import com.ning.http.client.Response import com.ning.http.client.Response
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import java.nio.channels.ClosedChannelException import java.nio.channels.ClosedChannelException
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
@ -62,7 +62,7 @@ class Netty38ClientTest extends HttpClientTest<Request> implements AgentTestTrai
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
// TODO(anuraaga): Do we also need to test ListenableFuture callback? // TODO(anuraaga): Do we also need to test ListenableFuture callback?
client.executeRequest(request, new AsyncCompletionHandler<Void>() { client.executeRequest(request, new AsyncCompletionHandler<Void>() {
@Override @Override
@ -95,7 +95,7 @@ class Netty38ClientTest extends HttpClientTest<Request> implements AgentTestTrai
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
switch (uri.toString()) { switch (uri.toString()) {
case "http://localhost:61/": // unopened port case "http://localhost:61/": // unopened port
exception = exception.getCause() != null ? exception.getCause() : new ConnectException("Connection refused: localhost/127.0.0.1:61") exception = exception.getCause() != null ? exception.getCause() : new ConnectException("Connection refused: localhost/127.0.0.1:61")
@ -103,7 +103,7 @@ class Netty38ClientTest extends HttpClientTest<Request> implements AgentTestTrai
case "https://192.0.2.1/": // non routable address case "https://192.0.2.1/": // non routable address
exception = exception.getCause() != null ? exception.getCause() : new ClosedChannelException() exception = exception.getCause() != null ? exception.getCause() : new ClosedChannelException()
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -22,6 +22,7 @@ import io.netty.handler.timeout.ReadTimeoutHandler
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import spock.lang.Shared import spock.lang.Shared
@ -86,7 +87,7 @@ class Netty40ClientTest extends HttpClientTest<DefaultFullHttpRequest> implement
} }
@Override @Override
void sendRequestWithCallback(DefaultFullHttpRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(DefaultFullHttpRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
Channel ch Channel ch
try { try {
ch = getBootstrap(uri).connect(uri.host, getPort(uri)).sync().channel() ch = getBootstrap(uri).connect(uri.host, getPort(uri)).sync().channel()

View File

@ -30,7 +30,8 @@ import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.HttpClientTracingHandler import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.HttpClientTracingHandler
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -114,7 +115,7 @@ class Netty41ClientTest extends HttpClientTest<DefaultFullHttpRequest> implement
} }
@Override @Override
void sendRequestWithCallback(DefaultFullHttpRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(DefaultFullHttpRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
Channel ch Channel ch
try { try {
ch = getBootstrap(uri).connect(uri.host, getPort(uri)).sync().channel() ch = getBootstrap(uri).connect(uri.host, getPort(uri)).sync().channel()

View File

@ -20,7 +20,7 @@ import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import io.opentelemetry.instrumentation.test.base.SingleConnection; import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Map; import java.util.Map;

View File

@ -12,6 +12,7 @@ import com.squareup.okhttp.Response
import com.squareup.okhttp.internal.http.HttpMethod import com.squareup.okhttp.internal.http.HttpMethod
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import spock.lang.Shared import spock.lang.Shared
@ -39,7 +40,7 @@ class OkHttp2Test extends HttpClientTest<Request> implements AgentTestTrait {
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
client.newCall(request).enqueue(new Callback() { client.newCall(request).enqueue(new Callback() {
@Override @Override
void onFailure(Request req, IOException e) { void onFailure(Request req, IOException e) {

View File

@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.okhttp.v3_0
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import okhttp3.Call import okhttp3.Call
@ -48,7 +49,7 @@ abstract class AbstractOkHttp3Test extends HttpClientTest<Request> {
} }
@Override @Override
void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Request request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
client.newCall(request).enqueue(new Callback() { client.newCall(request).enqueue(new Callback() {
@Override @Override
void onFailure(Call call, IOException e) { void onFailure(Call call, IOException e) {

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import java.util.concurrent.CompletionStage import java.util.concurrent.CompletionStage
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import play.libs.ws.StandaloneWSClient import play.libs.ws.StandaloneWSClient
@ -36,7 +36,7 @@ class PlayJavaWsClientTestBase extends PlayWsClientTestBaseBase<StandaloneWSRequ
} }
@Override @Override
void sendRequestWithCallback(StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, HttpClientTest.RequestResult requestResult) { void sendRequestWithCallback(StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.execute().whenComplete { response, throwable -> request.execute().whenComplete { response, throwable ->
requestResult.complete({ response.status }, throwable) requestResult.complete({ response.status }, throwable)
} }
@ -69,7 +69,7 @@ class PlayJavaStreamedWsClientTestBase extends PlayWsClientTestBaseBase<Standalo
} }
@Override @Override
void sendRequestWithCallback(StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, HttpClientTest.RequestResult requestResult) { void sendRequestWithCallback(StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
internalSendRequest(request).whenComplete { response, throwable -> internalSendRequest(request).whenComplete { response, throwable ->
requestResult.complete({ response.status }, throwable?.getCause()) requestResult.complete({ response.status }, throwable?.getCause())
} }
@ -120,7 +120,7 @@ class PlayScalaWsClientTestBase extends PlayWsClientTestBaseBase<play.api.libs.w
} }
@Override @Override
void sendRequestWithCallback(play.api.libs.ws.StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, HttpClientTest.RequestResult requestResult) { void sendRequestWithCallback(play.api.libs.ws.StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.execute().onComplete(new Function1<Try<play.api.libs.ws.StandaloneWSResponse>, Void>() { request.execute().onComplete(new Function1<Try<play.api.libs.ws.StandaloneWSResponse>, Void>() {
@Override @Override
Void apply(Try<play.api.libs.ws.StandaloneWSResponse> response) { Void apply(Try<play.api.libs.ws.StandaloneWSResponse> response) {
@ -161,7 +161,7 @@ class PlayScalaStreamedWsClientTestBase extends PlayWsClientTestBaseBase<play.ap
} }
@Override @Override
void sendRequestWithCallback(play.api.libs.ws.StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, HttpClientTest.RequestResult requestResult) { void sendRequestWithCallback(play.api.libs.ws.StandaloneWSRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
internalSendRequest(request).onComplete(new Function1<Try<play.api.libs.ws.StandaloneWSResponse>, Void>() { internalSendRequest(request).onComplete(new Function1<Try<play.api.libs.ws.StandaloneWSResponse>, Void>() {
@Override @Override
Void apply(Try<play.api.libs.ws.StandaloneWSResponse> response) { Void apply(Try<play.api.libs.ws.StandaloneWSResponse> response) {

View File

@ -8,7 +8,8 @@ package client
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CompletionStage import java.util.concurrent.CompletionStage
import play.libs.ws.WS import play.libs.ws.WS
@ -41,7 +42,7 @@ class PlayWsClientTest extends HttpClientTest<WSRequest> implements AgentTestTra
} }
@Override @Override
void sendRequestWithCallback(WSRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(WSRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
internalSendRequest(request, method).whenComplete { response, throwable -> internalSendRequest(request, method).whenComplete { response, throwable ->
requestResult.complete({ response.status }, throwable) requestResult.complete({ response.status }, throwable)
} }

View File

@ -9,9 +9,9 @@ import io.netty.channel.ConnectTimeoutException
import io.netty.handler.timeout.ReadTimeoutException import io.netty.handler.timeout.ReadTimeoutException
import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.time.Duration import java.time.Duration
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
@ -69,7 +69,7 @@ class RatpackHttpClientTest extends HttpClientTest<Void> implements AgentTestTra
} }
@Override @Override
void sendRequestWithCallback(Void request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(Void request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
exec.execute(Operation.of { exec.execute(Operation.of {
internalSendRequest(client, method, uri, headers).result {result -> internalSendRequest(client, method, uri, headers).result {result ->
requestResult.complete({ result.value }, result.throwable) requestResult.complete({ result.value }, result.throwable)
@ -122,16 +122,13 @@ class RatpackHttpClientTest extends HttpClientTest<Void> implements AgentTestTra
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
// non routable address
if (uri.toString() == "https://192.0.2.1/") { if (uri.toString() == "https://192.0.2.1/") {
spanAssert.errorEvent(ConnectTimeoutException, ~/connection timed out:/) return new ConnectTimeoutException("connection timed out: /192.0.2.1:443")
return
} else if (uri.getPath() == "/read-timeout") { } else if (uri.getPath() == "/read-timeout") {
spanAssert.errorEvent(ReadTimeoutException) return new ReadTimeoutException()
return
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -5,7 +5,7 @@
package client package client
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import ratpack.http.client.HttpClient import ratpack.http.client.HttpClient
class RatpackPooledHttpClientTest extends RatpackHttpClientTest { class RatpackPooledHttpClientTest extends RatpackHttpClientTest {

View File

@ -12,8 +12,8 @@ import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import reactor.netty.http.client.HttpClient import reactor.netty.http.client.HttpClient
@ -51,7 +51,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
} }
@Override @Override
void sendRequestWithCallback(HttpClient.ResponseReceiver request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpClient.ResponseReceiver request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.responseSingle {resp, content -> request.responseSingle {resp, content ->
// Make sure to consume content since that's when we close the span. // Make sure to consume content since that's when we close the span.
content.map { resp } content.map { resp }
@ -74,7 +74,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
if (exception.class.getName().endsWith("ReactiveException")) { if (exception.class.getName().endsWith("ReactiveException")) {
switch (uri.toString()) { switch (uri.toString()) {
case "http://localhost:61/": // unopened port case "http://localhost:61/": // unopened port
@ -82,7 +82,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
exception = exception.getCause() exception = exception.getCause()
} }
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -6,7 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9 package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
import reactor.netty.http.client.HttpClient import reactor.netty.http.client.HttpClient

View File

@ -17,8 +17,8 @@ import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.sdk.trace.data.SpanData
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import reactor.netty.http.client.HttpClient import reactor.netty.http.client.HttpClient
@ -56,7 +56,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
} }
@Override @Override
void sendRequestWithCallback(HttpClient.ResponseReceiver request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpClient.ResponseReceiver request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.responseSingle {resp, content -> request.responseSingle {resp, content ->
// Make sure to consume content since that's when we close the span. // Make sure to consume content since that's when we close the span.
content.map { resp } content.map { resp }
@ -79,7 +79,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
if (exception.class.getName().endsWith("ReactiveException")) { if (exception.class.getName().endsWith("ReactiveException")) {
switch (uri.toString()) { switch (uri.toString()) {
case "http://localhost:61/": // unopened port case "http://localhost:61/": // unopened port
@ -87,7 +87,7 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
exception = exception.getCause() exception = exception.getCause()
} }
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -6,7 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0 package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
import reactor.netty.http.client.HttpClient import reactor.netty.http.client.HttpClient

View File

@ -6,6 +6,7 @@
import io.opentelemetry.instrumentation.spring.httpclients.RestTemplateInterceptor import io.opentelemetry.instrumentation.spring.httpclients.RestTemplateInterceptor
import io.opentelemetry.instrumentation.test.LibraryTestTrait import io.opentelemetry.instrumentation.test.LibraryTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import org.springframework.http.HttpEntity import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
@ -43,7 +44,7 @@ class RestTemplateInstrumentationTest extends HttpClientTest<HttpEntity<String>>
} }
@Override @Override
void sendRequestWithCallback(HttpEntity<String> request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpEntity<String> request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
try { try {
restTemplate.execute(uri, HttpMethod.valueOf(method), { req -> restTemplate.execute(uri, HttpMethod.valueOf(method), { req ->
headers.forEach(req.getHeaders().&add) headers.forEach(req.getHeaders().&add)

View File

@ -7,7 +7,7 @@ package client
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod

View File

@ -7,9 +7,9 @@ package client
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.http.client.reactive.ReactorClientHttpConnector
import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.WebClient
@ -49,7 +49,7 @@ class SpringWebfluxHttpClientTest extends HttpClientTest<WebClient.RequestBodySp
} }
@Override @Override
void sendRequestWithCallback(WebClient.RequestBodySpec request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(WebClient.RequestBodySpec request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.exchange().subscribe({ request.exchange().subscribe({
requestResult.complete(it.statusCode().value()) requestResult.complete(it.statusCode().value())
}, { }, {
@ -58,7 +58,7 @@ class SpringWebfluxHttpClientTest extends HttpClientTest<WebClient.RequestBodySp
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
if (!exception.getClass().getName().endsWith("WebClientRequestException")) { if (!exception.getClass().getName().endsWith("WebClientRequestException")) {
switch (uri.toString()) { switch (uri.toString()) {
case "http://localhost:61/": // unopened port case "http://localhost:61/": // unopened port
@ -70,7 +70,7 @@ class SpringWebfluxHttpClientTest extends HttpClientTest<WebClient.RequestBodySp
exception = exception.getCause() exception = exception.getCause()
} }
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -7,7 +7,8 @@ package client
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.vertx.core.Vertx import io.vertx.core.Vertx
import io.vertx.core.VertxOptions import io.vertx.core.VertxOptions
import io.vertx.core.http.HttpClientOptions import io.vertx.core.http.HttpClientOptions
@ -52,7 +53,7 @@ class VertxHttpClientTest extends HttpClientTest<HttpClientRequest> implements A
} }
@Override @Override
void sendRequestWithCallback(HttpClientRequest request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpClientRequest request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
sendRequest(request).whenComplete { status, throwable -> sendRequest(request).whenComplete { status, throwable ->
requestResult.complete({ status }, throwable) requestResult.complete({ status }, throwable)
} }

View File

@ -5,7 +5,7 @@
package client; package client;
import io.opentelemetry.instrumentation.test.base.SingleConnection; import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection;
import io.vertx.core.Vertx; import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions; import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClient;

View File

@ -7,7 +7,8 @@ package client
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.vertx.circuitbreaker.CircuitBreakerOptions import io.vertx.circuitbreaker.CircuitBreakerOptions
import io.vertx.core.AsyncResult import io.vertx.core.AsyncResult
import io.vertx.core.VertxOptions import io.vertx.core.VertxOptions
@ -70,7 +71,7 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest<HttpRequest<?>>
} }
@Override @Override
void sendRequestWithCallback(HttpRequest<?> request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpRequest<?> request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
sendRequestWithCallback(request) { sendRequestWithCallback(request) {
if (it.succeeded()) { if (it.succeeded()) {
requestResult.complete(it.result().statusCode()) requestResult.complete(it.result().statusCode())

View File

@ -6,9 +6,9 @@
package client package client
import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
import io.vertx.core.VertxOptions import io.vertx.core.VertxOptions
import io.vertx.core.http.HttpMethod import io.vertx.core.http.HttpMethod
import io.vertx.ext.web.client.WebClientOptions import io.vertx.ext.web.client.WebClientOptions
@ -41,7 +41,7 @@ class VertxRxWebClientTest extends HttpClientTest<HttpRequest<Buffer>> implement
} }
@Override @Override
void sendRequestWithCallback(HttpRequest<Buffer> request, String method, URI uri, Map<String, String> headers, RequestResult requestResult) { void sendRequestWithCallback(HttpRequest<Buffer> request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
request.rxSend() request.rxSend()
.subscribe(new io.reactivex.functions.Consumer<HttpResponse<?>>() { .subscribe(new io.reactivex.functions.Consumer<HttpResponse<?>>() {
@Override @Override
@ -57,7 +57,7 @@ class VertxRxWebClientTest extends HttpClientTest<HttpRequest<Buffer>> implement
} }
@Override @Override
void assertClientSpanErrorEvent(SpanAssert spanAssert, URI uri, Throwable exception) { Throwable clientSpanError(URI uri, Throwable exception) {
if (exception.class == RuntimeException) { if (exception.class == RuntimeException) {
switch (uri.toString()) { switch (uri.toString()) {
case "http://localhost:61/": // unopened port case "http://localhost:61/": // unopened port
@ -65,7 +65,7 @@ class VertxRxWebClientTest extends HttpClientTest<HttpRequest<Buffer>> implement
exception = exception.getCause() exception = exception.getCause()
} }
} }
super.assertClientSpanErrorEvent(spanAssert, uri, exception) return exception
} }
@Override @Override

View File

@ -5,7 +5,7 @@
package client; package client;
import io.opentelemetry.instrumentation.test.base.SingleConnection; import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection;
import io.vertx.core.VertxOptions; import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.client.WebClientOptions; import io.vertx.ext.web.client.WebClientOptions;

View File

@ -16,7 +16,8 @@ sourceSets {
dependencies { dependencies {
api("org.codehaus.groovy:groovy-all") api("org.codehaus.groovy:groovy-all")
api("org.spockframework:spock-core") api("org.spockframework:spock-core")
implementation("org.junit.jupiter:junit-jupiter-api") api("org.junit.jupiter:junit-jupiter-api")
api("org.junit.jupiter:junit-jupiter-params")
api("io.opentelemetry:opentelemetry-api") api("io.opentelemetry:opentelemetry-api")
api("io.opentelemetry:opentelemetry-semconv") api("io.opentelemetry:opentelemetry-semconv")
@ -27,6 +28,9 @@ dependencies {
api("org.assertj:assertj-core") api("org.assertj:assertj-core")
// Needs to be api dependency due to Spock restriction.
api("org.awaitility:awaitility")
compileOnly(project(path = ":testing:armeria-shaded-for-testing", configuration = "shadow")) compileOnly(project(path = ":testing:armeria-shaded-for-testing", configuration = "shadow"))
implementation("io.opentelemetry:opentelemetry-proto") { implementation("io.opentelemetry:opentelemetry-proto") {
@ -39,7 +43,6 @@ dependencies {
implementation("net.bytebuddy:byte-buddy-agent") implementation("net.bytebuddy:byte-buddy-agent")
implementation("org.slf4j:slf4j-api") implementation("org.slf4j:slf4j-api")
implementation("ch.qos.logback:logback-classic") implementation("ch.qos.logback:logback-classic")
implementation("org.awaitility:awaitility")
implementation("org.slf4j:log4j-over-slf4j") implementation("org.slf4j:log4j-over-slf4j")
implementation("org.slf4j:jcl-over-slf4j") implementation("org.slf4j:jcl-over-slf4j")
implementation("org.slf4j:jul-to-slf4j") implementation("org.slf4j:jul-to-slf4j")

View File

@ -5,13 +5,11 @@
package io.opentelemetry.instrumentation.test.utils package io.opentelemetry.instrumentation.test.utils
import io.opentelemetry.api.GlobalOpenTelemetry import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.trace.Span import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.api.trace.Tracer import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.extension.annotations.WithSpan
import io.opentelemetry.instrumentation.test.server.ServerTraceUtils import io.opentelemetry.instrumentation.test.server.ServerTraceUtils
import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable
import java.util.concurrent.Callable import java.util.concurrent.Callable
@ -57,13 +55,6 @@ class TraceUtils {
tracer.spanBuilder(spanName).startSpan().end() tracer.spanBuilder(spanName).startSpan().end()
} }
// Must create span within agent using annotation until
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1726
@WithSpan(value = "parent-client-span", kind = SpanKind.CLIENT)
static <T> T runUnderParentClientSpan(Callable<T> r) {
r.call()
}
static <T> T runUnderTraceWithoutExceptionCatch(String spanName, Callable<T> r) { static <T> T runUnderTraceWithoutExceptionCatch(String spanName, Callable<T> r) {
Span span = tracer.spanBuilder(spanName).setSpanKind(SpanKind.INTERNAL).startSpan() Span span = tracer.spanBuilder(spanName).setSpanKind(SpanKind.INTERNAL).startSpan()

View File

@ -5,12 +5,22 @@
package io.opentelemetry.instrumentation.testing; package io.opentelemetry.instrumentation.testing;
import static org.awaitility.Awaitility.await;
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil;
import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable; import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable;
import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier; import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
import io.opentelemetry.sdk.testing.assertj.TracesAssert;
import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.SpanData;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.StreamSupport;
import org.awaitility.core.ConditionTimeoutException;
/** /**
* This interface defines a common set of operations for interaction with OpenTelemetry SDK and * This interface defines a common set of operations for interaction with OpenTelemetry SDK and
@ -34,6 +44,43 @@ public interface InstrumentationTestRunner {
boolean forceFlushCalled(); boolean forceFlushCalled();
/** Return a list of all captured traces, where each trace is a sorted list of spans. */
default List<List<SpanData>> traces() {
return TelemetryDataUtil.groupTraces(getExportedSpans());
}
default List<List<SpanData>> waitForTraces(int numberOfTraces) {
try {
return TelemetryDataUtil.waitForTraces(
this::getExportedSpans, numberOfTraces, 20, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException e) {
throw new AssertionError("Error waiting for " + numberOfTraces + " traces", e);
}
}
default void waitAndAssertTraces(Consumer<TraceAssert>... assertions) {
try {
await()
.untilAsserted(
() -> {
List<List<SpanData>> traces = waitForTraces(assertions.length);
TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(assertions);
});
} catch (ConditionTimeoutException e) {
// Don't throw this failure since the stack is the awaitility thread, causing confusion.
// Instead, just assert one more time on the test thread, which will fail with a better stack
// trace.
// TODO(anuraaga): There is probably a better way to do this.
List<List<SpanData>> traces = waitForTraces(assertions.length);
TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(assertions);
}
}
default void waitAndAssertTraces(Iterable<? extends Consumer<TraceAssert>> assertions) {
waitAndAssertTraces(
StreamSupport.stream(assertions.spliterator(), false).toArray(Consumer[]::new));
}
/** /**
* Runs the provided {@code callback} inside the scope of an INTERNAL span with name {@code * Runs the provided {@code callback} inside the scope of an INTERNAL span with name {@code
* spanName}. * spanName}.

View File

@ -11,14 +11,12 @@ import static org.awaitility.Awaitility.await;
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.ContextStorage;
import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner; import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner;
import io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil;
import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable; import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable;
import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier; import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier;
import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.SpanData;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.assertj.core.api.ListAssert; import org.assertj.core.api.ListAssert;
import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterAllCallback;
@ -38,7 +36,7 @@ public abstract class InstrumentationExtension
} }
@Override @Override
public void beforeAll(ExtensionContext extensionContext) { public void beforeAll(ExtensionContext extensionContext) throws Exception {
testRunner.beforeTestClass(); testRunner.beforeTestClass();
} }
@ -56,7 +54,7 @@ public abstract class InstrumentationExtension
} }
@Override @Override
public void afterAll(ExtensionContext extensionContext) { public void afterAll(ExtensionContext extensionContext) throws Exception {
testRunner.afterTestClass(); testRunner.afterTestClass();
} }
@ -70,11 +68,6 @@ public abstract class InstrumentationExtension
return testRunner.getExportedSpans(); return testRunner.getExportedSpans();
} }
/** Return a list of all captured traces, where each trace is a sorted list of spans. */
public List<List<SpanData>> traces() {
return TelemetryDataUtil.groupTraces(spans());
}
/** Return a list of all captured metrics. */ /** Return a list of all captured metrics. */
public List<MetricData> metrics() { public List<MetricData> metrics() {
return testRunner.getExportedMetrics(); return testRunner.getExportedMetrics();
@ -100,9 +93,8 @@ public abstract class InstrumentationExtension
} }
/** /**
* Removes all captured telemetry data. After calling this method {@link #spans()}, {@link * Removes all captured telemetry data. After calling this method {@link #spans()} and {@link
* #traces()} and {@link #metrics()} will return empty lists until more telemetry data is * #metrics()} will return empty lists until more telemetry data is captured.
* captured.
*/ */
public void clearData() { public void clearData() {
testRunner.clearAllExportedData(); testRunner.clearAllExportedData();
@ -112,25 +104,14 @@ public abstract class InstrumentationExtension
* Wait until at least {@code numberOfTraces} traces are completed and return all captured traces. * Wait until at least {@code numberOfTraces} traces are completed and return all captured traces.
* Note that there may be more than {@code numberOfTraces} collected. By default this waits up to * Note that there may be more than {@code numberOfTraces} collected. By default this waits up to
* 20 seconds, then times out. * 20 seconds, then times out.
*
* @throws TimeoutException when the operation times out
* @throws InterruptedException when the current thread is interrupted
*/ */
public List<List<SpanData>> waitForTraces(int numberOfTraces) public List<List<SpanData>> waitForTraces(int numberOfTraces) {
throws TimeoutException, InterruptedException { return testRunner.waitForTraces(numberOfTraces);
return waitForTraces(numberOfTraces, DEFAULT_TRACE_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} }
/** @SafeVarargs
* Wait until at least {@code numberOfTraces} traces are completed and return all captured traces. public final void waitAndAssertTraces(Consumer<TraceAssert>... assertions) {
* Note that there may be more than {@code numberOfTraces} collected. testRunner.waitAndAssertTraces(assertions);
*
* @throws TimeoutException when the operation times out
* @throws InterruptedException when the current thread is interrupted
*/
public List<List<SpanData>> waitForTraces(int numberOfTraces, long timeout, TimeUnit unit)
throws TimeoutException, InterruptedException {
return TelemetryDataUtil.waitForTraces(this::spans, numberOfTraces, timeout, unit);
} }
/** /**
@ -186,4 +167,8 @@ public abstract class InstrumentationExtension
String spanName, ThrowingSupplier<T, E> callback) throws E { String spanName, ThrowingSupplier<T, E> callback) throws E {
return testRunner.runWithServerSpan(spanName, callback); return testRunner.runWithServerSpan(spanName, callback);
} }
protected InstrumentationTestRunner getTestRunner() {
return testRunner;
}
} }

View File

@ -0,0 +1,69 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.testing.junit.http;
import io.opentelemetry.instrumentation.testing.AgentTestRunner;
import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner;
import io.opentelemetry.instrumentation.testing.LibraryTestRunner;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import org.junit.jupiter.api.extension.ExtensionContext;
/**
* A {@link InstrumentationExtension} which sets up infrastructure, such as a test HTTP server, for
* {@link AbstractHttpClientTest}.
*/
public final class HttpClientInstrumentationExtension extends InstrumentationExtension {
/**
* Returns a {@link InstrumentationExtension} to be used with {@link AbstractHttpClientTest} for
* javaagent instrumentation.
*/
public static InstrumentationExtension forAgent() {
return new HttpClientInstrumentationExtension(AgentTestRunner.instance());
}
/**
* Returns a {@link InstrumentationExtension} to be used with {@link AbstractHttpClientTest} for
* library instrumentation.
*/
public static InstrumentationExtension forLibrary() {
return new HttpClientInstrumentationExtension(LibraryTestRunner.instance());
}
private final HttpClientTestServer server;
private HttpClientInstrumentationExtension(InstrumentationTestRunner runner) {
super(runner);
server = new HttpClientTestServer(getOpenTelemetry());
}
@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
super.beforeAll(extensionContext);
server.beforeAll(extensionContext);
}
@Override
public void beforeEach(ExtensionContext extensionContext) {
super.beforeEach(extensionContext);
Object testInstance = extensionContext.getRequiredTestInstance();
if (!(testInstance instanceof AbstractHttpClientTest)) {
throw new AssertionError(
"HttpClientLibraryInstrumentationExtension can only be applied to a subclass of "
+ "AbstractHttpClientTest");
}
((AbstractHttpClientTest<?>) testInstance).setTesting(getTestRunner(), server);
}
@Override
public void afterAll(ExtensionContext extensionContext) throws Exception {
super.afterAll(extensionContext);
server.afterAll(extensionContext);
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.testing.junit.http;
import static io.opentelemetry.api.trace.SpanKind.SERVER;
import static io.opentelemetry.testing.internal.armeria.common.MediaType.PLAIN_TEXT_UTF_8;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.test.server.http.RequestContextGetter;
import io.opentelemetry.testing.internal.armeria.common.HttpData;
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
import io.opentelemetry.testing.internal.armeria.common.ResponseHeaders;
import io.opentelemetry.testing.internal.armeria.common.ResponseHeadersBuilder;
import io.opentelemetry.testing.internal.armeria.server.ServerBuilder;
import io.opentelemetry.testing.internal.armeria.server.logging.LoggingService;
import io.opentelemetry.testing.internal.armeria.testing.junit5.server.ServerExtension;
import java.io.FileInputStream;
import java.net.URI;
import java.security.KeyStore;
import java.time.Duration;
import javax.net.ssl.KeyManagerFactory;
public final class HttpClientTestServer extends ServerExtension {
private final OpenTelemetry openTelemetry;
private final Tracer tracer;
public HttpClientTestServer(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
tracer = openTelemetry.getTracer("test");
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(
new FileInputStream(System.getProperty("javax.net.ssl.trustStore")),
"testing".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, "testing".toCharArray());
sb.http(0)
.https(0)
.tls(kmf)
.service(
"/success",
(ctx, req) -> {
ResponseHeadersBuilder headers = ResponseHeaders.builder(HttpStatus.OK);
String testRequestId = req.headers().get("test-request-id");
if (testRequestId != null) {
headers.set("test-request-id", testRequestId);
}
return HttpResponse.of(headers.build(), HttpData.ofAscii("Hello."));
})
.service(
"/client-error",
(ctx, req) -> HttpResponse.of(HttpStatus.BAD_REQUEST, PLAIN_TEXT_UTF_8, "Invalid RQ"))
.service(
"/error",
(ctx, req) ->
HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR, PLAIN_TEXT_UTF_8, "Sorry."))
.service("/redirect", (ctx, req) -> HttpResponse.ofRedirect(HttpStatus.FOUND, "/success"))
.service(
"/another-redirect",
(ctx, req) -> HttpResponse.ofRedirect(HttpStatus.FOUND, "/redirect"))
.service(
"/circular-redirect",
(ctx, req) -> HttpResponse.ofRedirect(HttpStatus.FOUND, "/circular-redirect"))
.service(
"/secured",
(ctx, req) -> {
String auth = req.headers().get(AbstractHttpClientTest.BASIC_AUTH_KEY);
if (auth != null && auth.equals(AbstractHttpClientTest.BASIC_AUTH_VAL)) {
return HttpResponse.of(
HttpStatus.OK, PLAIN_TEXT_UTF_8, "secured string under basic auth");
}
return HttpResponse.of(HttpStatus.UNAUTHORIZED, PLAIN_TEXT_UTF_8, "Unauthorized");
})
.service("/to-secured", (ctx, req) -> HttpResponse.ofRedirect(HttpStatus.FOUND, "/secured"))
.service(
"/read-timeout",
(ctx, req) ->
HttpResponse.delayed(HttpResponse.of(HttpStatus.OK), Duration.ofSeconds(20)))
.decorator(
(delegate, ctx, req) -> {
for (String field : openTelemetry.getPropagators().getTextMapPropagator().fields()) {
if (req.headers().getAll(field).size() > 1) {
throw new AssertionError((Object) ("more than one " + field + " header present"));
}
}
SpanBuilder span =
tracer
.spanBuilder("test-http-server")
.setSpanKind(SERVER)
.setParent(
openTelemetry
.getPropagators()
.getTextMapPropagator()
.extract(Context.current(), ctx, RequestContextGetter.INSTANCE));
String traceRequestId = req.headers().get("test-request-id");
if (traceRequestId != null) {
span.setAttribute("test.request.id", Integer.parseInt(traceRequestId));
}
span.startSpan().end();
return delegate.serve(ctx, req);
})
.decorator(LoggingService.newDecorator());
}
URI resolveAddress(String path) {
return URI.create("http://localhost:" + httpPort() + path);
}
}

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package io.opentelemetry.instrumentation.test.base; package io.opentelemetry.instrumentation.testing.junit.http;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;