Migrate Ratpack HTTP Client tests to Java. (#3768)
* Migrate Ratpack HTTP Client tests to Java. * Close harness
This commit is contained in:
parent
40490a8a0f
commit
49c20ef724
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import java.time.Duration
|
|
||||||
import ratpack.exec.Promise
|
|
||||||
import ratpack.http.client.HttpClient
|
|
||||||
|
|
||||||
class RatpackForkedHttpClientTest extends RatpackHttpClientTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Promise<Integer> internalSendRequest(HttpClient client, String method, URI uri, Map<String, String> headers) {
|
|
||||||
def resp = client.request(uri) { spec ->
|
|
||||||
// Connect timeout for the whole client was added in 1.5 so we need to add timeout for each request
|
|
||||||
spec.connectTimeout(Duration.ofSeconds(2))
|
|
||||||
if (uri.getPath() == "/read-timeout") {
|
|
||||||
spec.readTimeout(Duration.ofMillis(READ_TIMEOUT_MS))
|
|
||||||
}
|
|
||||||
spec.method(method)
|
|
||||||
spec.headers { headersSpec ->
|
|
||||||
headers.entrySet().each {
|
|
||||||
headersSpec.add(it.key, it.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp.fork().map {
|
|
||||||
it.status.code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import io.netty.channel.ConnectTimeoutException
|
|
||||||
import io.netty.handler.timeout.ReadTimeoutException
|
|
||||||
import io.opentelemetry.api.common.AttributeKey
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
|
||||||
import java.time.Duration
|
|
||||||
import java.util.concurrent.ExecutionException
|
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
import ratpack.exec.Operation
|
|
||||||
import ratpack.exec.Promise
|
|
||||||
import ratpack.func.Action
|
|
||||||
import ratpack.http.client.HttpClient
|
|
||||||
import ratpack.http.client.HttpClientSpec
|
|
||||||
import ratpack.test.exec.ExecHarness
|
|
||||||
import spock.lang.AutoCleanup
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
class RatpackHttpClientTest extends HttpClientTest<Void> implements AgentTestTrait {
|
|
||||||
|
|
||||||
@AutoCleanup
|
|
||||||
@Shared
|
|
||||||
ExecHarness exec = ExecHarness.harness()
|
|
||||||
|
|
||||||
@AutoCleanup
|
|
||||||
@Shared
|
|
||||||
def client = buildHttpClient()
|
|
||||||
|
|
||||||
@AutoCleanup
|
|
||||||
@Shared
|
|
||||||
def singleConnectionClient = buildHttpClient({spec ->
|
|
||||||
spec.poolSize(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
HttpClient buildHttpClient() {
|
|
||||||
return buildHttpClient(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient buildHttpClient(Action<? super HttpClientSpec> action) {
|
|
||||||
HttpClient.of {
|
|
||||||
// execController method added in 1.9
|
|
||||||
if (HttpClientSpec.metaClass.getMetaMethod("execController") != null) {
|
|
||||||
it.execController(exec.getController())
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
action.execute(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Void buildRequest(String method, URI uri, Map<String, String> headers) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int sendRequest(Void request, String method, URI uri, Map<String, String> headers) {
|
|
||||||
return exec.yield {
|
|
||||||
internalSendRequest(client, method, uri, headers)
|
|
||||||
}.valueOrThrow
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void sendRequestWithCallback(Void request, String method, URI uri, Map<String, String> headers, AbstractHttpClientTest.RequestResult requestResult) {
|
|
||||||
exec.execute(Operation.of {
|
|
||||||
internalSendRequest(client, method, uri, headers).result {result ->
|
|
||||||
requestResult.complete({ result.value }, result.throwable)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// overridden in RatpackForkedHttpClientTest
|
|
||||||
Promise<Integer> internalSendRequest(HttpClient client, String method, URI uri, Map<String, String> headers) {
|
|
||||||
def resp = client.request(uri) { spec ->
|
|
||||||
// Connect timeout for the whole client was added in 1.5 so we need to add timeout for each request
|
|
||||||
spec.connectTimeout(Duration.ofSeconds(2))
|
|
||||||
if (uri.getPath() == "/read-timeout") {
|
|
||||||
spec.readTimeout(Duration.ofMillis(READ_TIMEOUT_MS))
|
|
||||||
}
|
|
||||||
spec.method(method)
|
|
||||||
spec.headers { headersSpec ->
|
|
||||||
headers.entrySet().each {
|
|
||||||
headersSpec.add(it.key, it.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp.map {
|
|
||||||
it.status.code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
|
||||||
return new SingleConnection() {
|
|
||||||
@Override
|
|
||||||
int doRequest(String path, Map<String, String> headers) throws ExecutionException, InterruptedException, TimeoutException {
|
|
||||||
def uri = resolveAddress(path)
|
|
||||||
return exec.yield {
|
|
||||||
internalSendRequest(singleConnectionClient, "GET", uri, headers)
|
|
||||||
}.valueOrThrow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String expectedClientSpanName(URI uri, String method) {
|
|
||||||
switch (uri.toString()) {
|
|
||||||
case "http://localhost:61/": // unopened port
|
|
||||||
case "https://192.0.2.1/": // non routable address
|
|
||||||
return "CONNECT"
|
|
||||||
default:
|
|
||||||
return super.expectedClientSpanName(uri, method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Throwable clientSpanError(URI uri, Throwable exception) {
|
|
||||||
if (uri.toString() == "https://192.0.2.1/") {
|
|
||||||
return new ConnectTimeoutException("connection timed out: /192.0.2.1:443")
|
|
||||||
} else if (uri.getPath() == "/read-timeout") {
|
|
||||||
return new ReadTimeoutException()
|
|
||||||
}
|
|
||||||
return exception
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Set<AttributeKey<?>> httpAttributes(URI uri) {
|
|
||||||
switch (uri.toString()) {
|
|
||||||
case "http://localhost:61/": // unopened port
|
|
||||||
case "https://192.0.2.1/": // non routable address
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return super.httpAttributes(uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean testRedirects() {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean testReusedRequest() {
|
|
||||||
// these tests will pass, but they don't really test anything since REQUEST is Void
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean testReadTimeout() {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
|
||||||
import ratpack.http.client.HttpClient
|
|
||||||
|
|
||||||
class RatpackPooledHttpClientTest extends RatpackHttpClientTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
HttpClient buildHttpClient() {
|
|
||||||
return buildHttpClient({spec ->
|
|
||||||
spec.poolSize(5)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
|
||||||
// this test is already run for RatpackHttpClientTest
|
|
||||||
// returning null here to avoid running the same test twice
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackForkedHttpClientTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
class RatpackForkedHttpClientTest extends AbstractRatpackForkedHttpClientTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackHttpClientTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
class RatpackHttpClientTest extends AbstractRatpackHttpClientTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackPooledHttpClientTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
class RatpackPooledHttpClientTest extends AbstractRatpackPooledHttpClientTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ dependencies {
|
||||||
api(project(":testing-common"))
|
api(project(":testing-common"))
|
||||||
|
|
||||||
api("io.ratpack:ratpack-core:1.4.0")
|
api("io.ratpack:ratpack-core:1.4.0")
|
||||||
|
api("io.ratpack:ratpack-test:1.4.0")
|
||||||
|
|
||||||
implementation("org.codehaus.groovy:groovy-all")
|
implementation("org.codehaus.groovy:groovy-all")
|
||||||
implementation("io.opentelemetry:opentelemetry-api")
|
implementation("io.opentelemetry:opentelemetry-api")
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.ratpack.client;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
import ratpack.exec.Promise;
|
||||||
|
import ratpack.http.client.HttpClient;
|
||||||
|
import ratpack.http.client.ReceivedResponse;
|
||||||
|
|
||||||
|
public abstract class AbstractRatpackForkedHttpClientTest extends AbstractRatpackHttpClientTest {
|
||||||
|
@Override
|
||||||
|
protected final Promise<Integer> internalSendRequest(
|
||||||
|
HttpClient client, String method, URI uri, Map<String, String> headers) {
|
||||||
|
Promise<ReceivedResponse> resp =
|
||||||
|
client.request(
|
||||||
|
uri,
|
||||||
|
spec -> {
|
||||||
|
// Connect timeout for the whole client was added in 1.5 so we need to add timeout for
|
||||||
|
// each request
|
||||||
|
spec.connectTimeout(Duration.ofSeconds(2));
|
||||||
|
if (uri.getPath().equals("/read-timeout")) {
|
||||||
|
spec.readTimeout(readTimeout());
|
||||||
|
}
|
||||||
|
spec.method(method);
|
||||||
|
spec.headers(headersSpec -> headers.forEach(headersSpec::add));
|
||||||
|
});
|
||||||
|
|
||||||
|
return resp.fork().map(ReceivedResponse::getStatusCode);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.ratpack.client;
|
||||||
|
|
||||||
|
import io.netty.channel.ConnectTimeoutException;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutException;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import ratpack.exec.ExecController;
|
||||||
|
import ratpack.exec.Operation;
|
||||||
|
import ratpack.exec.Promise;
|
||||||
|
import ratpack.func.Action;
|
||||||
|
import ratpack.http.client.HttpClient;
|
||||||
|
import ratpack.http.client.HttpClientSpec;
|
||||||
|
import ratpack.http.client.ReceivedResponse;
|
||||||
|
import ratpack.test.exec.ExecHarness;
|
||||||
|
|
||||||
|
public abstract class AbstractRatpackHttpClientTest extends AbstractHttpClientTest<Void> {
|
||||||
|
|
||||||
|
private final ExecHarness exec = ExecHarness.harness();
|
||||||
|
|
||||||
|
private HttpClient client;
|
||||||
|
private HttpClient singleConnectionClient;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
void setUpClient() throws Exception {
|
||||||
|
client = buildHttpClient();
|
||||||
|
singleConnectionClient = buildHttpClient(spec -> spec.poolSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
void cleanUpClient() {
|
||||||
|
client.close();
|
||||||
|
singleConnectionClient.close();
|
||||||
|
exec.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpClient buildHttpClient() throws Exception {
|
||||||
|
return buildHttpClient(Action.noop());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpClient buildHttpClient(Action<? super HttpClientSpec> action) throws Exception {
|
||||||
|
return HttpClient.of(
|
||||||
|
spec -> {
|
||||||
|
// execController method added in 1.9
|
||||||
|
try {
|
||||||
|
Method execController =
|
||||||
|
HttpClientSpec.class.getMethod("execController", ExecController.class);
|
||||||
|
execController.invoke(spec, exec.getController());
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
action.execute(spec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Void buildRequest(String method, URI uri, Map<String, String> headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final int sendRequest(Void request, String method, URI uri, Map<String, String> headers)
|
||||||
|
throws Exception {
|
||||||
|
return exec.yield(unused -> internalSendRequest(client, method, uri, headers))
|
||||||
|
.getValueOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void sendRequestWithCallback(
|
||||||
|
Void request,
|
||||||
|
String method,
|
||||||
|
URI uri,
|
||||||
|
Map<String, String> headers,
|
||||||
|
RequestResult requestResult)
|
||||||
|
throws Exception {
|
||||||
|
exec.execute(
|
||||||
|
Operation.of(
|
||||||
|
() ->
|
||||||
|
internalSendRequest(client, method, uri, headers)
|
||||||
|
.result(
|
||||||
|
result ->
|
||||||
|
requestResult.complete(result::getValue, result.getThrowable()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// overridden in RatpackForkedHttpClientTest
|
||||||
|
protected Promise<Integer> internalSendRequest(
|
||||||
|
HttpClient client, String method, URI uri, Map<String, String> headers) {
|
||||||
|
Promise<ReceivedResponse> resp =
|
||||||
|
client.request(
|
||||||
|
uri,
|
||||||
|
spec -> {
|
||||||
|
// Connect timeout for the whole client was added in 1.5 so we need to add timeout for
|
||||||
|
// each request
|
||||||
|
spec.connectTimeout(Duration.ofSeconds(2));
|
||||||
|
if (uri.getPath().equals("/read-timeout")) {
|
||||||
|
spec.readTimeout(readTimeout());
|
||||||
|
}
|
||||||
|
spec.method(method);
|
||||||
|
spec.headers(headersSpec -> headers.forEach(headersSpec::add));
|
||||||
|
});
|
||||||
|
|
||||||
|
return resp.map(ReceivedResponse::getStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpClientTestOptions options) {
|
||||||
|
options.setSingleConnectionFactory(
|
||||||
|
(host, port) ->
|
||||||
|
(path, headers) -> {
|
||||||
|
URI uri = resolveAddress(path);
|
||||||
|
return exec.yield(
|
||||||
|
unused -> internalSendRequest(singleConnectionClient, "GET", uri, headers))
|
||||||
|
.getValueOrThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
options.setExpectedClientSpanNameMapper(
|
||||||
|
(uri, method) -> {
|
||||||
|
switch (uri.toString()) {
|
||||||
|
case "http://localhost:61/": // unopened port
|
||||||
|
case "https://192.0.2.1/": // non routable address
|
||||||
|
return "CONNECT";
|
||||||
|
default:
|
||||||
|
return HttpClientTestOptions.DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER.apply(
|
||||||
|
uri, method);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.setClientSpanErrorMapper(
|
||||||
|
(uri, exception) -> {
|
||||||
|
if (uri.toString().equals("https://192.0.2.1/")) {
|
||||||
|
return new ConnectTimeoutException("connection timed out: /192.0.2.1:443");
|
||||||
|
} else if (uri.getPath().equals("/read-timeout")) {
|
||||||
|
return ReadTimeoutException.INSTANCE;
|
||||||
|
}
|
||||||
|
return exception;
|
||||||
|
});
|
||||||
|
|
||||||
|
options.setHttpAttributes(
|
||||||
|
uri -> {
|
||||||
|
switch (uri.toString()) {
|
||||||
|
case "http://localhost:61/": // unopened port
|
||||||
|
case "https://192.0.2.1/": // non routable address
|
||||||
|
return Collections.emptySet();
|
||||||
|
default:
|
||||||
|
return HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.disableTestRedirects();
|
||||||
|
|
||||||
|
// these tests will pass, but they don't really test anything since REQUEST is Void
|
||||||
|
options.disableTestReusedRequest();
|
||||||
|
|
||||||
|
options.enableTestReadTimeout();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.ratpack.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions;
|
||||||
|
import ratpack.http.client.HttpClient;
|
||||||
|
|
||||||
|
public abstract class AbstractRatpackPooledHttpClientTest extends AbstractRatpackHttpClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpClient buildHttpClient() throws Exception {
|
||||||
|
return buildHttpClient(spec -> spec.poolSize(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpClientTestOptions options) {
|
||||||
|
super.configure(options);
|
||||||
|
|
||||||
|
// this test is already run for RatpackHttpClientTest
|
||||||
|
// returning null here to avoid running the same test twice
|
||||||
|
options.setSingleConnectionFactory((host, port) -> null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -115,14 +115,15 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
* dedicated API for invoking synchronously, such as OkHttp's execute method.
|
* dedicated API for invoking synchronously, such as OkHttp's execute method.
|
||||||
*/
|
*/
|
||||||
protected abstract int sendRequest(
|
protected abstract int sendRequest(
|
||||||
REQUEST request, String method, URI uri, Map<String, String> headers);
|
REQUEST request, String method, URI uri, Map<String, String> headers) throws Exception;
|
||||||
|
|
||||||
protected void sendRequestWithCallback(
|
protected void sendRequestWithCallback(
|
||||||
REQUEST request,
|
REQUEST request,
|
||||||
String method,
|
String method,
|
||||||
URI uri,
|
URI uri,
|
||||||
Map<String, String> headers,
|
Map<String, String> headers,
|
||||||
RequestResult requestResult) {
|
RequestResult requestResult)
|
||||||
|
throws Exception {
|
||||||
// Must be implemented if testAsync is true
|
// Must be implemented if testAsync is true
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
@ -210,7 +211,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {"/success", "/success?with=params"})
|
@ValueSource(strings = {"/success", "/success?with=params"})
|
||||||
void successfulGetRequest(String path) {
|
void successfulGetRequest(String path) throws Exception {
|
||||||
URI uri = resolveAddress(path);
|
URI uri = resolveAddress(path);
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
int responseCode = doRequest(method, uri);
|
int responseCode = doRequest(method, uri);
|
||||||
|
@ -233,7 +234,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {"PUT", "POST"})
|
@ValueSource(strings = {"PUT", "POST"})
|
||||||
void successfulRequestWithParent(String method) {
|
void successfulRequestWithParent(String method) throws Exception {
|
||||||
URI uri = resolveAddress("/success");
|
URI uri = resolveAddress("/success");
|
||||||
int responseCode = testing.runWithSpan("parent", () -> doRequest(method, uri));
|
int responseCode = testing.runWithSpan("parent", () -> doRequest(method, uri));
|
||||||
|
|
||||||
|
@ -258,7 +259,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void successfulRequestWithNotSampledParent() throws InterruptedException {
|
void successfulRequestWithNotSampledParent() throws Exception {
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
URI uri = resolveAddress("/success");
|
URI uri = resolveAddress("/success");
|
||||||
int responseCode = testing.runWithNonRecordingSpan(() -> doRequest(method, uri));
|
int responseCode = testing.runWithNonRecordingSpan(() -> doRequest(method, uri));
|
||||||
|
@ -361,7 +362,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void basicRequestWith1Redirect() {
|
void basicRequestWith1Redirect() throws Exception {
|
||||||
// TODO quite a few clients create an extra span for the redirect
|
// TODO quite a few clients create an extra span for the redirect
|
||||||
// This test should handle both types or we should unify how the clients work
|
// This test should handle both types or we should unify how the clients work
|
||||||
|
|
||||||
|
@ -390,7 +391,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void basicRequestWith2Redirects() {
|
void basicRequestWith2Redirects() throws Exception {
|
||||||
// TODO quite a few clients create an extra span for the redirect
|
// TODO quite a few clients create an extra span for the redirect
|
||||||
// This test should handle both types or we should unify how the clients work
|
// This test should handle both types or we should unify how the clients work
|
||||||
|
|
||||||
|
@ -457,7 +458,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void redirectToSecuredCopiesAuthHeader() {
|
void redirectToSecuredCopiesAuthHeader() throws Exception {
|
||||||
assumeTrue(options.testRedirects);
|
assumeTrue(options.testRedirects);
|
||||||
|
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
|
@ -514,7 +515,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void reuseRequest() {
|
void reuseRequest() throws Exception {
|
||||||
assumeTrue(options.testReusedRequest);
|
assumeTrue(options.testReusedRequest);
|
||||||
|
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
|
@ -556,7 +557,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
// (so that it propagates the same trace id / span id that it reports to the backend
|
// (so that it propagates the same trace id / span id that it reports to the backend
|
||||||
// and the trace is not broken)
|
// and the trace is not broken)
|
||||||
@Test
|
@Test
|
||||||
void requestWithExistingTracingHeaders() {
|
void requestWithExistingTracingHeaders() throws Exception {
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
URI uri = resolveAddress("/success");
|
URI uri = resolveAddress("/success");
|
||||||
|
|
||||||
|
@ -619,7 +620,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void connectionErrorUnopenedPortWithCallback() {
|
void connectionErrorUnopenedPortWithCallback() throws Exception {
|
||||||
assumeTrue(options.testConnectionFailure);
|
assumeTrue(options.testConnectionFailure);
|
||||||
assumeTrue(options.testCallback);
|
assumeTrue(options.testCallback);
|
||||||
assumeTrue(options.testErrorWithCallback);
|
assumeTrue(options.testErrorWithCallback);
|
||||||
|
@ -745,7 +746,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
matches = ".*IBM J9 VM.*",
|
matches = ".*IBM J9 VM.*",
|
||||||
disabledReason = "IBM JVM has different protocol support for TLS")
|
disabledReason = "IBM JVM has different protocol support for TLS")
|
||||||
@Test
|
@Test
|
||||||
void httpsRequest() {
|
void httpsRequest() throws Exception {
|
||||||
assumeTrue(options.testRemoteConnection);
|
assumeTrue(options.testRemoteConnection);
|
||||||
assumeTrue(options.testHttps);
|
assumeTrue(options.testHttps);
|
||||||
|
|
||||||
|
@ -796,15 +797,19 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
testing.runWithSpan(
|
try {
|
||||||
"Parent span " + index,
|
testing.runWithSpan(
|
||||||
() -> {
|
"Parent span " + index,
|
||||||
Span.current().setAttribute("test.request.id", index);
|
() -> {
|
||||||
doRequest(
|
Span.current().setAttribute("test.request.id", index);
|
||||||
method,
|
doRequest(
|
||||||
uri,
|
method,
|
||||||
Collections.singletonMap("test-request-id", String.valueOf(index)));
|
uri,
|
||||||
});
|
Collections.singletonMap("test-request-id", String.valueOf(index)));
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
pool.submit(job);
|
pool.submit(job);
|
||||||
}
|
}
|
||||||
|
@ -870,16 +875,20 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
testing.runWithSpan(
|
try {
|
||||||
"Parent span " + index,
|
testing.runWithSpan(
|
||||||
() -> {
|
"Parent span " + index,
|
||||||
Span.current().setAttribute("test.request.id", index);
|
() -> {
|
||||||
doRequestWithCallback(
|
Span.current().setAttribute("test.request.id", index);
|
||||||
method,
|
doRequestWithCallback(
|
||||||
uri,
|
method,
|
||||||
Collections.singletonMap("test-request-id", String.valueOf(index)),
|
uri,
|
||||||
() -> testing.runWithSpan("child", () -> {}));
|
Collections.singletonMap("test-request-id", String.valueOf(index)),
|
||||||
});
|
() -> testing.runWithSpan("child", () -> {}));
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
pool.submit(job);
|
pool.submit(job);
|
||||||
});
|
});
|
||||||
|
@ -1007,7 +1016,7 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
// Visible for spock bridge.
|
// Visible for spock bridge.
|
||||||
SpanDataAssert assertClientSpan(
|
SpanDataAssert assertClientSpan(
|
||||||
SpanDataAssert span, URI uri, String method, Integer responseCode) {
|
SpanDataAssert span, URI uri, String method, Integer responseCode) {
|
||||||
Set<AttributeKey<?>> httpClientAttributes = httpAttributes(uri);
|
Set<AttributeKey<?>> httpClientAttributes = options.httpAttributes.apply(uri);
|
||||||
return span.hasName(options.expectedClientSpanNameMapper.apply(uri, method))
|
return span.hasName(options.expectedClientSpanNameMapper.apply(uri, method))
|
||||||
.hasKind(SpanKind.CLIENT)
|
.hasKind(SpanKind.CLIENT)
|
||||||
.hasAttributesSatisfying(
|
.hasAttributesSatisfying(
|
||||||
|
@ -1255,22 +1264,22 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
.toArray(new Consumer[0]);
|
.toArray(new Consumer[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doRequest(String method, URI uri) {
|
private int doRequest(String method, URI uri) throws Exception {
|
||||||
return doRequest(method, uri, Collections.emptyMap());
|
return doRequest(method, uri, Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doRequest(String method, URI uri, Map<String, String> headers) {
|
private int doRequest(String method, URI uri, Map<String, String> headers) throws Exception {
|
||||||
REQUEST request = buildRequest(method, uri, headers);
|
REQUEST request = buildRequest(method, uri, headers);
|
||||||
return sendRequest(request, method, uri, headers);
|
return sendRequest(request, method, uri, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doReusedRequest(String method, URI uri) {
|
private int doReusedRequest(String method, URI uri) throws Exception {
|
||||||
REQUEST request = buildRequest(method, uri, Collections.emptyMap());
|
REQUEST request = buildRequest(method, uri, Collections.emptyMap());
|
||||||
sendRequest(request, method, uri, Collections.emptyMap());
|
sendRequest(request, method, uri, Collections.emptyMap());
|
||||||
return sendRequest(request, method, uri, Collections.emptyMap());
|
return sendRequest(request, method, uri, Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doRequestWithExistingTracingHeaders(String method, URI uri) {
|
private int doRequestWithExistingTracingHeaders(String method, URI uri) throws Exception {
|
||||||
Map<String, String> headers = new HashMap();
|
Map<String, String> headers = new HashMap();
|
||||||
for (String field :
|
for (String field :
|
||||||
testing.getOpenTelemetry().getPropagators().getTextMapPropagator().fields()) {
|
testing.getOpenTelemetry().getPropagators().getTextMapPropagator().fields()) {
|
||||||
|
@ -1280,20 +1289,20 @@ public abstract class AbstractHttpClientTest<REQUEST> {
|
||||||
return sendRequest(request, method, uri, headers);
|
return sendRequest(request, method, uri, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestResult doRequestWithCallback(String method, URI uri, Runnable callback) {
|
private RequestResult doRequestWithCallback(String method, URI uri, Runnable callback)
|
||||||
|
throws Exception {
|
||||||
return doRequestWithCallback(method, uri, Collections.emptyMap(), callback);
|
return doRequestWithCallback(method, uri, Collections.emptyMap(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestResult doRequestWithCallback(
|
private RequestResult doRequestWithCallback(
|
||||||
String method, URI uri, Map<String, String> headers, Runnable callback) {
|
String method, URI uri, Map<String, String> headers, Runnable callback) throws Exception {
|
||||||
REQUEST request = buildRequest(method, uri, headers);
|
REQUEST request = buildRequest(method, uri, headers);
|
||||||
RequestResult requestResult = new RequestResult(callback);
|
RequestResult requestResult = new RequestResult(callback);
|
||||||
sendRequestWithCallback(request, method, uri, headers, requestResult);
|
sendRequestWithCallback(request, method, uri, headers, requestResult);
|
||||||
return requestResult;
|
return requestResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for spock bridge.
|
protected URI resolveAddress(String path) {
|
||||||
URI resolveAddress(String path) {
|
|
||||||
return URI.create("http://localhost:" + server.httpPort() + path);
|
return URI.create("http://localhost:" + server.httpPort() + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,13 @@ public final class HttpClientTestOptions {
|
||||||
SemanticAttributes.HTTP_FLAVOR,
|
SemanticAttributes.HTTP_FLAVOR,
|
||||||
SemanticAttributes.HTTP_USER_AGENT)));
|
SemanticAttributes.HTTP_USER_AGENT)));
|
||||||
|
|
||||||
|
public static final BiFunction<URI, String, String> DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER =
|
||||||
|
(uri, method) -> method != null ? "HTTP " + method : "HTTP request";
|
||||||
|
|
||||||
Function<URI, Set<AttributeKey<?>>> httpAttributes = unused -> DEFAULT_HTTP_ATTRIBUTES;
|
Function<URI, Set<AttributeKey<?>>> httpAttributes = unused -> DEFAULT_HTTP_ATTRIBUTES;
|
||||||
|
|
||||||
BiFunction<URI, String, String> expectedClientSpanNameMapper =
|
BiFunction<URI, String, String> expectedClientSpanNameMapper =
|
||||||
(uri, method) -> method != null ? "HTTP " + method : "HTTP request";
|
DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER;
|
||||||
|
|
||||||
Integer responseCodeOnRedirectError = null;
|
Integer responseCodeOnRedirectError = null;
|
||||||
String userAgent = null;
|
String userAgent = null;
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
package io.opentelemetry.instrumentation.testing.junit.http;
|
package io.opentelemetry.instrumentation.testing.junit.http;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for http client tests which require a single connection.
|
* Helper class for http client tests which require a single connection.
|
||||||
|
@ -24,6 +22,5 @@ import java.util.concurrent.TimeoutException;
|
||||||
public interface SingleConnection {
|
public interface SingleConnection {
|
||||||
String REQUEST_ID_HEADER = "test-request-id";
|
String REQUEST_ID_HEADER = "test-request-id";
|
||||||
|
|
||||||
int doRequest(String path, Map<String, String> headers)
|
int doRequest(String path, Map<String, String> headers) throws Exception;
|
||||||
throws ExecutionException, InterruptedException, TimeoutException;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue