Merge pull request #1320 from DataDog/tyler/http-client-testing

Add tests for http clients
This commit is contained in:
Brian Devins-Suresh 2020-03-25 16:08:26 -04:00 committed by GitHub
commit de4b6d7733
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 364 additions and 36 deletions

View File

@ -9,7 +9,9 @@ import datadog.trace.api.DDSpanTypes
import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.bootstrap.instrumentation.api.Tags
import datadog.trace.instrumentation.akkahttp.AkkaHttpClientDecorator import datadog.trace.instrumentation.akkahttp.AkkaHttpClientDecorator
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class AkkaHttpClientInstrumentationTest extends HttpClientTest { class AkkaHttpClientInstrumentationTest extends HttpClientTest {
@Shared @Shared
@ -56,6 +58,12 @@ class AkkaHttpClientInstrumentationTest extends HttpClientTest {
false false
} }
@Override
boolean testRemoteConnection() {
// Not sure how to properly set timeouts...
return false
}
def "singleRequest exception trace"() { def "singleRequest exception trace"() {
when: when:
// Passing null causes NPE in singleRequest // Passing null causes NPE in singleRequest

View File

@ -1,19 +1,28 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator
import org.apache.http.HttpResponse import org.apache.http.HttpResponse
import org.apache.http.client.config.RequestConfig
import org.apache.http.concurrent.FutureCallback import org.apache.http.concurrent.FutureCallback
import org.apache.http.impl.nio.client.HttpAsyncClients import org.apache.http.impl.nio.client.HttpAsyncClients
import org.apache.http.message.BasicHeader import org.apache.http.message.BasicHeader
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
@Timeout(5)
class ApacheHttpAsyncClientCallbackTest extends HttpClientTest { class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
@Shared
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(CONNECT_TIMEOUT_MS)
.setSocketTimeout(READ_TIMEOUT_MS)
.build()
@AutoCleanup @AutoCleanup
@Shared @Shared
def client = HttpAsyncClients.createDefault() def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
def setupSpec() { def setupSpec() {
client.start() client.start()
@ -59,4 +68,9 @@ class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
Integer statusOnRedirectError() { Integer statusOnRedirectError() {
return 302 return 302
} }
@Override
boolean testRemoteConnection() {
false // otherwise SocketTimeoutException for https requests
}
} }

View File

@ -1,17 +1,26 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator
import org.apache.http.client.config.RequestConfig
import org.apache.http.impl.nio.client.HttpAsyncClients import org.apache.http.impl.nio.client.HttpAsyncClients
import org.apache.http.message.BasicHeader import org.apache.http.message.BasicHeader
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.Future import java.util.concurrent.Future
@Timeout(5)
class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest { class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
@Shared
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(CONNECT_TIMEOUT_MS)
.setSocketTimeout(READ_TIMEOUT_MS)
.build()
@AutoCleanup @AutoCleanup
@Shared @Shared
def client = HttpAsyncClients.createDefault() def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
def setupSpec() { def setupSpec() {
client.start() client.start()
@ -45,4 +54,9 @@ class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
Integer statusOnRedirectError() { Integer statusOnRedirectError() {
return 302 return 302
} }
@Override
boolean testRemoteConnection() {
false // otherwise SocketTimeoutException for https requests
}
} }

View File

@ -1,17 +1,26 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator
import org.apache.http.HttpResponse import org.apache.http.HttpResponse
import org.apache.http.client.config.RequestConfig
import org.apache.http.concurrent.FutureCallback import org.apache.http.concurrent.FutureCallback
import org.apache.http.impl.nio.client.HttpAsyncClients import org.apache.http.impl.nio.client.HttpAsyncClients
import org.apache.http.message.BasicHeader import org.apache.http.message.BasicHeader
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class ApacheHttpAsyncClientTest extends HttpClientTest { class ApacheHttpAsyncClientTest extends HttpClientTest {
@Shared
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(CONNECT_TIMEOUT_MS)
.setSocketTimeout(READ_TIMEOUT_MS)
.build()
@AutoCleanup @AutoCleanup
@Shared @Shared
def client = HttpAsyncClients.createDefault() def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
def setupSpec() { def setupSpec() {
client.start() client.start()
@ -54,4 +63,9 @@ class ApacheHttpAsyncClientTest extends HttpClientTest {
Integer statusOnRedirectError() { Integer statusOnRedirectError() {
return 302 return 302
} }
@Override
boolean testRemoteConnection() {
false // otherwise SocketTimeoutException for https requests
}
} }

View File

@ -4,8 +4,12 @@ import org.apache.http.HttpResponse
import org.apache.http.client.ResponseHandler import org.apache.http.client.ResponseHandler
import org.apache.http.impl.client.DefaultHttpClient import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.message.BasicHeader import org.apache.http.message.BasicHeader
import org.apache.http.params.HttpConnectionParams
import org.apache.http.params.HttpParams
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class ApacheHttpClientResponseHandlerTest extends HttpClientTest { class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
@Shared @Shared
@ -19,6 +23,12 @@ class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
} }
} }
def setupSpec() {
HttpParams httpParams = client.getParams()
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
}
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
def request = new HttpUriRequest(method, uri) def request = new HttpUriRequest(method, uri)

View File

@ -6,13 +6,22 @@ import org.apache.http.HttpResponse
import org.apache.http.impl.client.DefaultHttpClient import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.message.BasicHeader import org.apache.http.message.BasicHeader
import org.apache.http.message.BasicHttpRequest import org.apache.http.message.BasicHttpRequest
import org.apache.http.params.HttpConnectionParams
import org.apache.http.params.HttpParams
import org.apache.http.protocol.BasicHttpContext import org.apache.http.protocol.BasicHttpContext
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTest { abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTest {
@Shared @Shared
def client = new DefaultHttpClient() def client = new DefaultHttpClient()
def setupSpec() {
HttpParams httpParams = client.getParams()
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
}
@Override @Override
String component() { String component() {
return ApacheHttpClientDecorator.DECORATE.component() return ApacheHttpClientDecorator.DECORATE.component()
@ -55,6 +64,7 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
} }
} }
@Timeout(5)
class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> { class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
@Override @Override
BasicHttpRequest createRequest(String method, URI uri) { BasicHttpRequest createRequest(String method, URI uri) {
@ -65,8 +75,14 @@ class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
HttpResponse executeRequest(BasicHttpRequest request, URI uri) { HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request) return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request)
} }
@Override
boolean testRemoteConnection() {
return false
}
} }
@Timeout(5)
class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpRequest> { class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpRequest> {
@Override @Override
BasicHttpRequest createRequest(String method, URI uri) { BasicHttpRequest createRequest(String method, URI uri) {
@ -77,8 +93,14 @@ class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpReque
HttpResponse executeRequest(BasicHttpRequest request, URI uri) { HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, new BasicHttpContext()) return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, new BasicHttpContext())
} }
@Override
boolean testRemoteConnection() {
return false
}
} }
@Timeout(5)
class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicHttpRequest> { class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicHttpRequest> {
@Override @Override
BasicHttpRequest createRequest(String method, URI uri) { BasicHttpRequest createRequest(String method, URI uri) {
@ -89,8 +111,14 @@ class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicH
HttpResponse executeRequest(BasicHttpRequest request, URI uri) { HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }) return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response })
} }
@Override
boolean testRemoteConnection() {
return false
}
} }
@Timeout(5)
class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest<BasicHttpRequest> { class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest<BasicHttpRequest> {
@Override @Override
BasicHttpRequest createRequest(String method, URI uri) { BasicHttpRequest createRequest(String method, URI uri) {
@ -101,8 +129,14 @@ class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest
HttpResponse executeRequest(BasicHttpRequest request, URI uri) { HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }, new BasicHttpContext()) return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }, new BasicHttpContext())
} }
@Override
boolean testRemoteConnection() {
return false
}
} }
@Timeout(5)
class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> { class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
@Override @Override
HttpUriRequest createRequest(String method, URI uri) { HttpUriRequest createRequest(String method, URI uri) {
@ -115,6 +149,7 @@ class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
} }
} }
@Timeout(5)
class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest> { class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest> {
@Override @Override
HttpUriRequest createRequest(String method, URI uri) { HttpUriRequest createRequest(String method, URI uri) {
@ -127,6 +162,7 @@ class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest>
} }
} }
@Timeout(5)
class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUriRequest> { class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUriRequest> {
@Override @Override
HttpUriRequest createRequest(String method, URI uri) { HttpUriRequest createRequest(String method, URI uri) {
@ -139,6 +175,7 @@ class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUri
} }
} }
@Timeout(5)
class ApacheClientUriRequestResponseHandlerContext extends ApacheHttpClientTest<HttpUriRequest> { class ApacheClientUriRequestResponseHandlerContext extends ApacheHttpClientTest<HttpUriRequest> {
@Override @Override
HttpUriRequest createRequest(String method, URI uri) { HttpUriRequest createRequest(String method, URI uri) {

View File

@ -10,11 +10,18 @@ import org.apache.commons.httpclient.methods.PostMethod
import org.apache.commons.httpclient.methods.PutMethod import org.apache.commons.httpclient.methods.PutMethod
import org.apache.commons.httpclient.methods.TraceMethod import org.apache.commons.httpclient.methods.TraceMethod
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class CommonsHttpClientTest extends HttpClientTest { class CommonsHttpClientTest extends HttpClientTest {
@Shared @Shared
HttpClient client = new HttpClient() HttpClient client = new HttpClient()
def setupSpec() {
client.setConnectionTimeout(CONNECT_TIMEOUT_MS)
client.setTimeout(READ_TIMEOUT_MS)
}
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
HttpMethod httpMethod HttpMethod httpMethod

View File

@ -23,6 +23,8 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest {
GenericUrl genericUrl = new GenericUrl(uri) GenericUrl genericUrl = new GenericUrl(uri)
HttpRequest request = requestFactory.buildRequest(method, genericUrl, null) HttpRequest request = requestFactory.buildRequest(method, genericUrl, null)
request.connectTimeout = CONNECT_TIMEOUT_MS
request.readTimeout = READ_TIMEOUT_MS
request.getHeaders().putAll(headers) request.getHeaders().putAll(headers)
request.setThrowExceptionOnExecuteError(throwExceptionOnError) request.setThrowExceptionOnExecuteError(throwExceptionOnError)

View File

@ -1,6 +1,8 @@
import com.google.api.client.http.HttpRequest import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpResponse import com.google.api.client.http.HttpResponse
import spock.lang.Timeout
@Timeout(5)
class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest { class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest {
@Override @Override
HttpResponse executeRequest(HttpRequest request) { HttpResponse executeRequest(HttpRequest request) {

View File

@ -1,9 +1,12 @@
import com.google.api.client.http.HttpRequest import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpResponse import com.google.api.client.http.HttpResponse
import spock.lang.Retry import spock.lang.Retry
import spock.lang.Timeout
@Retry @Retry(condition = { !invocation.method.name.contains('circular redirects') })
@Timeout(5)
class GoogleHttpClientTest extends AbstractGoogleHttpClientTest { class GoogleHttpClientTest extends AbstractGoogleHttpClientTest {
@Override @Override
HttpResponse executeRequest(HttpRequest request) { HttpResponse executeRequest(HttpRequest request) {
return request.execute() return request.execute()

View File

@ -1,6 +1,8 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator
import spock.lang.Timeout
@Timeout(5)
class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest { class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
@Override @Override
@ -8,6 +10,8 @@ class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
HttpURLConnection connection = uri.toURL().openConnection() HttpURLConnection connection = uri.toURL().openConnection()
try { try {
connection.setRequestMethod(method) connection.setRequestMethod(method)
connection.connectTimeout = CONNECT_TIMEOUT_MS
connection.readTimeout = READ_TIMEOUT_MS
headers.each { connection.setRequestProperty(it.key, it.value) } headers.each { connection.setRequestProperty(it.key, it.value) }
connection.setRequestProperty("Connection", "close") connection.setRequestProperty("Connection", "close")
return connection.getResponseCode() return connection.getResponseCode()

View File

@ -5,6 +5,7 @@ import datadog.trace.bootstrap.instrumentation.api.Tags
import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator
import spock.lang.Ignore import spock.lang.Ignore
import spock.lang.Requires import spock.lang.Requires
import spock.lang.Timeout
import sun.net.www.protocol.https.HttpsURLConnectionImpl import sun.net.www.protocol.https.HttpsURLConnectionImpl
import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride
@ -12,6 +13,7 @@ import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope
import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.OPERATION_NAME import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.OPERATION_NAME
@Timeout(5)
class HttpUrlConnectionTest extends HttpClientTest { class HttpUrlConnectionTest extends HttpClientTest {
static final RESPONSE = "Hello." static final RESPONSE = "Hello."
@ -25,6 +27,8 @@ class HttpUrlConnectionTest extends HttpClientTest {
headers.each { connection.setRequestProperty(it.key, it.value) } headers.each { connection.setRequestProperty(it.key, it.value) }
connection.setRequestProperty("Connection", "close") connection.setRequestProperty("Connection", "close")
connection.useCaches = true connection.useCaches = true
connection.connectTimeout = CONNECT_TIMEOUT_MS
connection.readTimeout = READ_TIMEOUT_MS
def parentSpan = activeScope() def parentSpan = activeScope()
def stream = connection.inputStream def stream = connection.inputStream
assert activeScope() == parentSpan assert activeScope() == parentSpan

View File

@ -1,8 +1,10 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator import datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionDecorator
import spock.lang.Timeout
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope
@Timeout(5)
class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest { class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
@Override @Override
@ -13,6 +15,8 @@ class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
headers.each { connection.setRequestProperty(it.key, it.value) } headers.each { connection.setRequestProperty(it.key, it.value) }
connection.setRequestProperty("Connection", "close") connection.setRequestProperty("Connection", "close")
connection.useCaches = false connection.useCaches = false
connection.connectTimeout = CONNECT_TIMEOUT_MS
connection.readTimeout = READ_TIMEOUT_MS
def parentSpan = activeScope() def parentSpan = activeScope()
def stream = connection.inputStream def stream = connection.inputStream
assert activeScope() == parentSpan assert activeScope() == parentSpan

View File

@ -4,13 +4,24 @@ 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
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.http.client.ClientHttpRequestFactory
import org.springframework.http.client.SimpleClientHttpRequestFactory
import org.springframework.web.client.RestTemplate import org.springframework.web.client.RestTemplate
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class SpringRestTemplateTest extends HttpClientTest { class SpringRestTemplateTest extends HttpClientTest {
@Shared @Shared
RestTemplate restTemplate = new RestTemplate() ClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory()
@Shared
RestTemplate restTemplate = new RestTemplate(factory)
def setupSpec() {
factory.connectTimeout = CONNECT_TIMEOUT_MS
factory.readTimeout = READ_TIMEOUT_MS
}
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
@ -36,4 +47,10 @@ class SpringRestTemplateTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
@Override
boolean testRemoteConnection() {
// FIXME: exception wrapped in ResourceAccessException
return false
}
} }

View File

@ -5,13 +5,17 @@ import com.sun.jersey.api.client.filter.LoggingFilter
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.jaxrs.v1.JaxRsClientV1Decorator import datadog.trace.instrumentation.jaxrs.v1.JaxRsClientV1Decorator
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
@Timeout(5)
class JaxRsClientV1Test extends HttpClientTest { class JaxRsClientV1Test extends HttpClientTest {
@Shared @Shared
Client client = Client.create() Client client = Client.create()
def setupSpec() { def setupSpec() {
client.setConnectTimeout(CONNECT_TIMEOUT_MS)
client.setReadTimeout(READ_TIMEOUT_MS)
// Add filters to ensure spans aren't duplicated. // Add filters to ensure spans aren't duplicated.
client.addFilter(new LoggingFilter()) client.addFilter(new LoggingFilter())
client.addFilter(new GZIPContentEncodingFilter()) client.addFilter(new GZIPContentEncodingFilter())

View File

@ -33,7 +33,8 @@ dependencies {
testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1' testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.0' testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.0'
testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.0.Final' testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.5.Final'
// ^ This version has timeouts https://issues.redhat.com/browse/RESTEASY-975
testCompile group: 'org.apache.cxf', name: 'cxf-rt-rs-client', version: '3.1.0' testCompile group: 'org.apache.cxf', name: 'cxf-rt-rs-client', version: '3.1.0'
// Doesn't work with CXF 3.0.x because their context is wrong: // Doesn't work with CXF 3.0.x because their context is wrong:
// https://github.com/apache/cxf/commit/335c7bad2436f08d6d54180212df5a52157c9f21 // https://github.com/apache/cxf/commit/335c7bad2436f08d6d54180212df5a52157c9f21

View File

@ -1,8 +1,11 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.jaxrs.JaxRsClientDecorator import datadog.trace.instrumentation.jaxrs.JaxRsClientDecorator
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
import org.glassfish.jersey.client.ClientConfig
import org.glassfish.jersey.client.ClientProperties
import org.glassfish.jersey.client.JerseyClientBuilder import org.glassfish.jersey.client.JerseyClientBuilder
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import spock.lang.Timeout
import javax.ws.rs.client.AsyncInvoker import javax.ws.rs.client.AsyncInvoker
import javax.ws.rs.client.Client import javax.ws.rs.client.Client
@ -12,6 +15,7 @@ import javax.ws.rs.client.InvocationCallback
import javax.ws.rs.client.WebTarget import javax.ws.rs.client.WebTarget
import javax.ws.rs.core.MediaType import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response import javax.ws.rs.core.Response
import java.util.concurrent.TimeUnit
abstract class JaxRsClientAsyncTest extends HttpClientTest { abstract class JaxRsClientAsyncTest extends HttpClientTest {
@ -51,11 +55,15 @@ abstract class JaxRsClientAsyncTest extends HttpClientTest {
abstract ClientBuilder builder() abstract ClientBuilder builder()
} }
@Timeout(5)
class JerseyClientAsyncTest extends JaxRsClientAsyncTest { class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
@Override @Override
ClientBuilder builder() { ClientBuilder builder() {
return new JerseyClientBuilder() ClientConfig config = new ClientConfig()
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
return new JerseyClientBuilder().withConfig(config)
} }
boolean testCircularRedirects() { boolean testCircularRedirects() {
@ -63,11 +71,14 @@ class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
} }
} }
@Timeout(5)
class ResteasyClientAsyncTest extends JaxRsClientAsyncTest { class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
@Override @Override
ClientBuilder builder() { ClientBuilder builder() {
return new ResteasyClientBuilder() return new ResteasyClientBuilder()
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
} }
boolean testRedirects() { boolean testRedirects() {
@ -75,6 +86,7 @@ class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
} }
} }
@Timeout(5)
class CxfClientAsyncTest extends JaxRsClientAsyncTest { class CxfClientAsyncTest extends JaxRsClientAsyncTest {
@Override @Override
@ -89,4 +101,9 @@ class CxfClientAsyncTest extends JaxRsClientAsyncTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: span not reported correctly.
false
}
} }

View File

@ -1,8 +1,11 @@
import datadog.trace.agent.test.base.HttpClientTest import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.jaxrs.JaxRsClientDecorator import datadog.trace.instrumentation.jaxrs.JaxRsClientDecorator
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
import org.glassfish.jersey.client.ClientConfig
import org.glassfish.jersey.client.ClientProperties
import org.glassfish.jersey.client.JerseyClientBuilder import org.glassfish.jersey.client.JerseyClientBuilder
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import spock.lang.Timeout
import javax.ws.rs.client.Client import javax.ws.rs.client.Client
import javax.ws.rs.client.ClientBuilder import javax.ws.rs.client.ClientBuilder
@ -11,6 +14,7 @@ import javax.ws.rs.client.Invocation
import javax.ws.rs.client.WebTarget import javax.ws.rs.client.WebTarget
import javax.ws.rs.core.MediaType import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response import javax.ws.rs.core.Response
import java.util.concurrent.TimeUnit
abstract class JaxRsClientTest extends HttpClientTest { abstract class JaxRsClientTest extends HttpClientTest {
@ -41,11 +45,15 @@ abstract class JaxRsClientTest extends HttpClientTest {
abstract ClientBuilder builder() abstract ClientBuilder builder()
} }
@Timeout(5)
class JerseyClientTest extends JaxRsClientTest { class JerseyClientTest extends JaxRsClientTest {
@Override @Override
ClientBuilder builder() { ClientBuilder builder() {
return new JerseyClientBuilder() ClientConfig config = new ClientConfig()
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
return new JerseyClientBuilder().withConfig(config)
} }
boolean testCircularRedirects() { boolean testCircularRedirects() {
@ -53,24 +61,29 @@ class JerseyClientTest extends JaxRsClientTest {
} }
} }
@Timeout(5)
class ResteasyClientTest extends JaxRsClientTest { class ResteasyClientTest extends JaxRsClientTest {
@Override @Override
ClientBuilder builder() { ClientBuilder builder() {
return new ResteasyClientBuilder() return new ResteasyClientBuilder()
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
} }
boolean testRedirects() { boolean testRedirects() {
false false
} }
} }
@Timeout(5)
class CxfClientTest extends JaxRsClientTest { class CxfClientTest extends JaxRsClientTest {
@Override @Override
ClientBuilder builder() { ClientBuilder builder() {
return new ClientBuilderImpl() return new ClientBuilderImpl()
// .property(ClientImpl.HTTP_CONNECTION_TIMEOUT_PROP, (long) CONNECT_TIMEOUT_MS)
// .property(ClientImpl.HTTP_RECEIVE_TIMEOUT_PROP, (long) READ_TIMEOUT_MS)
} }
boolean testRedirects() { boolean testRedirects() {
@ -80,4 +93,9 @@ class CxfClientTest extends JaxRsClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: span not reported correctly.
false
}
} }

View File

@ -7,6 +7,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
import org.asynchttpclient.Response import org.asynchttpclient.Response
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -16,6 +17,7 @@ import static datadog.trace.agent.test.utils.TraceUtils.basicSpan
import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
import static org.asynchttpclient.Dsl.asyncHttpClient import static org.asynchttpclient.Dsl.asyncHttpClient
@Timeout(5)
class Netty40ClientTest extends HttpClientTest { class Netty40ClientTest extends HttpClientTest {
@Shared @Shared
@ -60,6 +62,11 @@ class Netty40ClientTest extends HttpClientTest {
false false
} }
@Override
boolean testRemoteConnection() {
return false
}
def "connection error (unopened port)"() { def "connection error (unopened port)"() {
given: given:
def uri = new URI("http://localhost:$UNUSABLE_PORT/") def uri = new URI("http://localhost:$UNUSABLE_PORT/")

View File

@ -17,6 +17,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
import org.asynchttpclient.Response import org.asynchttpclient.Response
import spock.lang.Retry import spock.lang.Retry
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -27,6 +28,7 @@ import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
import static org.asynchttpclient.Dsl.asyncHttpClient import static org.asynchttpclient.Dsl.asyncHttpClient
@Retry @Retry
@Timeout(5)
class Netty41ClientTest extends HttpClientTest { class Netty41ClientTest extends HttpClientTest {
@Shared @Shared
@ -70,6 +72,11 @@ class Netty41ClientTest extends HttpClientTest {
false false
} }
@Override
boolean testRemoteConnection() {
return false
}
def "connection error (unopened port)"() { def "connection error (unopened port)"() {
given: given:
def uri = new URI("http://localhost:$UNUSABLE_PORT/") def uri = new URI("http://localhost:$UNUSABLE_PORT/")

View File

@ -6,10 +6,18 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.internal.http.HttpMethod import okhttp3.internal.http.HttpMethod
import spock.lang.Timeout
import java.util.concurrent.TimeUnit
@Timeout(5)
class OkHttp3Test extends HttpClientTest { class OkHttp3Test extends HttpClientTest {
def client = new OkHttpClient() def client = new OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.writeTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build()
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {

View File

@ -6,9 +6,11 @@ import play.libs.ws.WS
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Subject import spock.lang.Subject
import spock.lang.Timeout
// Play 2.6+ uses a separately versioned client that shades the underlying dependency // Play 2.6+ uses a separately versioned client that shades the underlying dependency
// This means our built in instrumentation won't work. // This means our built in instrumentation won't work.
@Timeout(5)
class PlayWSClientTest extends HttpClientTest { class PlayWSClientTest extends HttpClientTest {
@Subject @Subject
@Shared @Shared
@ -50,4 +52,9 @@ class PlayWSClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
@Override
boolean testRemoteConnection() {
return false
}
} }

View File

@ -8,9 +8,11 @@ import scala.concurrent.ExecutionContext
import scala.concurrent.Future import scala.concurrent.Future
import scala.concurrent.duration.Duration import scala.concurrent.duration.Duration
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@Timeout(5)
class PlayJavaWSClientTest extends PlayWSClientTestBase { class PlayJavaWSClientTest extends PlayWSClientTestBase {
@Shared @Shared
StandaloneWSClient wsClient StandaloneWSClient wsClient
@ -37,6 +39,7 @@ class PlayJavaWSClientTest extends PlayWSClientTestBase {
} }
} }
@Timeout(5)
class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase { class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
@Shared @Shared
StandaloneWSClient wsClient StandaloneWSClient wsClient
@ -66,6 +69,7 @@ class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
} }
} }
@Timeout(5)
class PlayScalaWSClientTest extends PlayWSClientTestBase { class PlayScalaWSClientTest extends PlayWSClientTestBase {
@Shared @Shared
play.api.libs.ws.StandaloneWSClient wsClient play.api.libs.ws.StandaloneWSClient wsClient
@ -96,6 +100,7 @@ class PlayScalaWSClientTest extends PlayWSClientTestBase {
} }
} }
@Timeout(5)
class PlayScalaStreamedWSClientTest extends PlayWSClientTestBase { class PlayScalaStreamedWSClientTest extends PlayWSClientTestBase {
@Shared @Shared
play.api.libs.ws.StandaloneWSClient wsClient play.api.libs.ws.StandaloneWSClient wsClient

View File

@ -7,7 +7,11 @@ import ratpack.http.client.HttpClient
import ratpack.test.exec.ExecHarness import ratpack.test.exec.ExecHarness
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import java.time.Duration
@Timeout(5)
class RatpackHttpClientTest extends HttpClientTest { class RatpackHttpClientTest extends HttpClientTest {
@AutoCleanup @AutoCleanup
@ -15,12 +19,16 @@ class RatpackHttpClientTest extends HttpClientTest {
ExecHarness exec = ExecHarness.harness() ExecHarness exec = ExecHarness.harness()
@Shared @Shared
def client = HttpClient.of {} def client = HttpClient.of {
it.readTimeout(Duration.ofSeconds(2))
// Connect timeout added in 1.5
}
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
ExecResult<Integer> result = exec.yield { ExecResult<Integer> result = exec.yield {
def resp = client.request(uri) { spec -> def resp = client.request(uri) { spec ->
spec.connectTimeout(Duration.ofSeconds(2))
spec.method(method) spec.method(method)
spec.headers { headersSpec -> spec.headers { headersSpec ->
headers.entrySet().each { headers.entrySet().each {
@ -55,4 +63,9 @@ class RatpackHttpClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
@Override
boolean testRemoteConnection() {
return false
}
} }

View File

@ -11,9 +11,11 @@ import org.springframework.http.HttpMethod
import org.springframework.web.reactive.function.client.ClientResponse import org.springframework.web.reactive.function.client.ClientResponse
import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.WebClient
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Timeout
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan
@Timeout(5)
class SpringWebfluxHttpClientTest extends HttpClientTest { class SpringWebfluxHttpClientTest extends HttpClientTest {
@Shared @Shared
@ -92,4 +94,9 @@ class SpringWebfluxHttpClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: figure out how to configure timeouts.
false
}
} }

View File

@ -4,7 +4,7 @@ import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
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.HttpClientOptions
import io.vertx.core.http.HttpClientResponse import io.vertx.core.http.HttpClientResponse
import io.vertx.core.http.HttpMethod import io.vertx.core.http.HttpMethod
import spock.lang.Shared import spock.lang.Shared
@ -16,9 +16,11 @@ import java.util.concurrent.CompletableFuture
class VertxHttpClientTest extends HttpClientTest { class VertxHttpClientTest extends HttpClientTest {
@Shared @Shared
Vertx vertx = Vertx.vertx(new VertxOptions()) def vertx = Vertx.vertx(new VertxOptions())
@Shared @Shared
HttpClient httpClient = vertx.createHttpClient() def clientOptions = new HttpClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
@Shared
def httpClient = vertx.createHttpClient(clientOptions)
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
@ -53,4 +55,9 @@ class VertxHttpClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: figure out how to configure timeouts.
false
}
} }

View File

@ -5,6 +5,7 @@ import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
import io.vertx.circuitbreaker.CircuitBreakerOptions import io.vertx.circuitbreaker.CircuitBreakerOptions
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.reactivex.circuitbreaker.CircuitBreaker import io.vertx.reactivex.circuitbreaker.CircuitBreaker
import io.vertx.reactivex.core.Vertx import io.vertx.reactivex.core.Vertx
import io.vertx.reactivex.ext.web.client.WebClient import io.vertx.reactivex.ext.web.client.WebClient
@ -19,7 +20,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
@Shared @Shared
Vertx vertx = Vertx.vertx(new VertxOptions()) Vertx vertx = Vertx.vertx(new VertxOptions())
@Shared @Shared
WebClient client = WebClient.create(vertx) def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
@Shared
WebClient client = WebClient.create(vertx, clientOptions)
@Shared @Shared
CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx, CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx,
new CircuitBreakerOptions() new CircuitBreakerOptions()
@ -69,4 +72,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: figure out how to configure timeouts.
false
}
} }

View File

@ -4,6 +4,7 @@ import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator import datadog.trace.instrumentation.netty41.client.NettyHttpClientDecorator
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.reactivex.core.Vertx import io.vertx.reactivex.core.Vertx
import io.vertx.reactivex.ext.web.client.WebClient import io.vertx.reactivex.ext.web.client.WebClient
import spock.lang.Shared import spock.lang.Shared
@ -15,7 +16,9 @@ class VertxRxWebClientTest extends HttpClientTest {
@Shared @Shared
Vertx vertx = Vertx.vertx(new VertxOptions()) Vertx vertx = Vertx.vertx(new VertxOptions())
@Shared @Shared
WebClient client = WebClient.create(vertx) def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
@Shared
WebClient client = WebClient.create(vertx, clientOptions)
@Override @Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) { int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
@ -48,4 +51,9 @@ class VertxRxWebClientTest extends HttpClientTest {
boolean testConnectionFailure() { boolean testConnectionFailure() {
false false
} }
boolean testRemoteConnection() {
// FIXME: figure out how to configure timeouts.
false
}
} }

View File

@ -8,6 +8,7 @@ import datadog.trace.api.DDSpanTypes
import datadog.trace.api.DDTags import datadog.trace.api.DDTags
import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.bootstrap.instrumentation.api.Tags
import spock.lang.AutoCleanup import spock.lang.AutoCleanup
import spock.lang.Requires
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Unroll import spock.lang.Unroll
@ -23,6 +24,8 @@ import static org.junit.Assume.assumeTrue
@Unroll @Unroll
abstract class HttpClientTest extends AgentTestRunner { abstract class HttpClientTest extends AgentTestRunner {
protected static final BODY_METHODS = ["POST", "PUT"] protected static final BODY_METHODS = ["POST", "PUT"]
protected static final CONNECT_TIMEOUT_MS = 1000
protected static final READ_TIMEOUT_MS = 2000
@AutoCleanup @AutoCleanup
@Shared @Shared
@ -109,7 +112,7 @@ abstract class HttpClientTest extends AgentTestRunner {
server.distributedRequestTrace(it, 0, trace(1).last()) server.distributedRequestTrace(it, 0, trace(1).last())
trace(1, size(2)) { trace(1, size(2)) {
basicSpan(it, 0, "parent") basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method, false) clientSpan(it, 1, span(0), method)
} }
} }
@ -179,7 +182,7 @@ abstract class HttpClientTest extends AgentTestRunner {
trace(0, size(3)) { trace(0, size(3)) {
basicSpan(it, 0, "parent") basicSpan(it, 0, "parent")
basicSpan(it, 1, "child", span(0)) basicSpan(it, 1, "child", span(0))
clientSpan(it, 2, span(0), method, false) clientSpan(it, 2, span(0), method)
} }
} }
@ -201,7 +204,7 @@ abstract class HttpClientTest extends AgentTestRunner {
// only one trace (client). // only one trace (client).
assertTraces(2) { assertTraces(2) {
trace(0, size(1)) { trace(0, size(1)) {
clientSpan(it, 0, null, method, false) clientSpan(it, 0, null, method)
} }
trace(1, 1) { trace(1, 1) {
basicSpan(it, 0, "callback") basicSpan(it, 0, "callback")
@ -262,8 +265,7 @@ abstract class HttpClientTest extends AgentTestRunner {
def "basic #method request with circular redirects"() { def "basic #method request with circular redirects"() {
given: given:
assumeTrue(testRedirects()) assumeTrue(testRedirects() && testCircularRedirects())
assumeTrue(testCircularRedirects())
def uri = server.address.resolve("/circular-redirect") def uri = server.address.resolve("/circular-redirect")
when: when:
@ -312,6 +314,77 @@ abstract class HttpClientTest extends AgentTestRunner {
method = "GET" method = "GET"
} }
def "connection error dropped request"() {
given:
assumeTrue(testRemoteConnection())
// https://stackoverflow.com/a/100859
def uri = new URI("http://www.google.com:81/")
when:
runUnderTrace("parent") {
doRequest(method, uri)
}
then:
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
assertTraces(1) {
trace(0, size(2)) {
basicSpan(it, 0, "parent", null, thrownException)
clientSpan(it, 1, span(0), method, false, false, uri, null, thrownException)
}
}
where:
method = "HEAD"
}
def "connection error non routable address"() {
given:
assumeTrue(testRemoteConnection())
def uri = new URI("https://192.0.2.1/")
when:
runUnderTrace("parent") {
doRequest(method, uri)
}
then:
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
assertTraces(1) {
trace(0, size(2)) {
basicSpan(it, 0, "parent", null, thrownException)
clientSpan(it, 1, span(0), method, false, false, uri, null, thrownException)
}
}
where:
method = "HEAD"
}
// IBM JVM has different protocol support for TLS
@Requires({ !System.getProperty("java.vm.name").contains("IBM J9 VM") })
def "test https request"() {
given:
assumeTrue(testRemoteConnection())
def uri = new URI("https://www.google.com/")
when:
def status = doRequest(method, uri)
then:
status == 200
assertTraces(1) {
trace(0, size(1)) {
clientSpan(it, 0, null, method, false, false, uri)
}
}
where:
method = "HEAD"
}
// parent span must be cast otherwise it breaks debugging classloading (junit loads it early) // parent span must be cast otherwise it breaks debugging classloading (junit loads it early)
void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean renameService = false, boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) { void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean renameService = false, boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) {
trace.span(index) { trace.span(index) {
@ -320,7 +393,7 @@ abstract class HttpClientTest extends AgentTestRunner {
} else { } else {
childOf((DDSpan) parentSpan) childOf((DDSpan) parentSpan)
} }
serviceName renameService ? "localhost" : "unnamed-java-app" serviceName renameService ? uri.host : "unnamed-java-app"
operationName expectedOperationName() operationName expectedOperationName()
resourceName "$method $uri.path" resourceName "$method $uri.path"
spanType DDSpanTypes.HTTP_CLIENT spanType DDSpanTypes.HTTP_CLIENT
@ -328,9 +401,9 @@ abstract class HttpClientTest extends AgentTestRunner {
tags { tags {
"$Tags.COMPONENT" component "$Tags.COMPONENT" component
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
"$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOSTNAME" uri.host
"$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional "$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional
"$Tags.PEER_PORT" uri.port "$Tags.PEER_PORT" uri.port > 0 ? uri.port : { it == null || it == 443 } // Optional
"$Tags.HTTP_URL" "${uri.resolve(uri.path)}" "$Tags.HTTP_URL" "${uri.resolve(uri.path)}"
"$Tags.HTTP_METHOD" method "$Tags.HTTP_METHOD" method
if (status) { if (status) {
@ -368,6 +441,10 @@ abstract class HttpClientTest extends AgentTestRunner {
true true
} }
boolean testRemoteConnection() {
true
}
boolean testCallbackWithParent() { boolean testCallbackWithParent() {
// FIXME: this hack is here because callback with parent is broken in play-ws when the stream() // FIXME: this hack is here because callback with parent is broken in play-ws when the stream()
// function is used. There is no way to stop a test from a derived class hence the flag // function is used. There is no way to stop a test from a derived class hence the flag

View File

@ -22,17 +22,14 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan
class TestHttpServer implements AutoCloseable { class TestHttpServer implements AutoCloseable {
static TestHttpServer httpServer(boolean start = true, static TestHttpServer httpServer(@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
def server = new TestHttpServer() def server = new TestHttpServer()
def clone = (Closure) spec.clone() def clone = (Closure) spec.clone()
clone.delegate = server clone.delegate = server
clone.resolveStrategy = Closure.DELEGATE_FIRST clone.resolveStrategy = Closure.DELEGATE_FIRST
clone(server) clone(server)
if (start) { server.start()
server.start()
}
return server return server
} }

View File

@ -18,12 +18,12 @@ class ServerTest extends AgentTestRunner {
def "test server lifecycle"() { def "test server lifecycle"() {
setup: setup:
def server = httpServer(startAutomatically) { def server = httpServer {
handlers {} handlers {}
} }
expect: expect:
server.internalServer.isRunning() == startAutomatically server.internalServer.isRunning()
when: when:
server.start() server.start()
@ -44,16 +44,13 @@ class ServerTest extends AgentTestRunner {
server.internalServer.isRunning() server.internalServer.isRunning()
when: when:
server.stop() server.close()
then: then:
!server.internalServer.isRunning() !server.internalServer.isRunning()
cleanup: cleanup:
server.stop() server.close()
where:
startAutomatically << [true, false]
} }
def "server 404's with no handlers"() { def "server 404's with no handlers"() {