Refactor HttpClientTest
* Remove unused extraClientSpans() method
* Merge extraAttributes() and hasClientSpanHttpAttributes(uri) into
httpAttributes(uri): this will allow to choose extracted attributes
per URI (for example, OkHttp won't set flavor on connection exception
once it's rewritten to Instrumenter)
MODIFY
instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/test/groovy/CommonsHttpClientTest.groovy
instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/test/groovy/CommonsHttpClientTest.groovy
@@ -92,10 +92,11 @@ class CommonsHttpClientTest extends HttpClientTest<HttpMethod> implements AgentT
}
@Override
- List<AttributeKey<?>> extraAttributes() {
- [
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
+ Set<AttributeKey<?>> extra = [
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_TARGET,
]
+ super.httpAttributes(uri) + extra
}
}

MODIFY
instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy
instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy
@@ -43,11 +43,12 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
}
@Override
- List<AttributeKey<?>> extraAttributes() {
- [
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
+ Set<AttributeKey<?>> extra = [
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_TARGET,
]
+ super.httpAttributes(uri) + extra
}
// compilation fails with @Override annotation on this method (groovy quirk?)

MODIFY
instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy
instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy
@@ -48,11 +48,12 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
}
@Override
- List<AttributeKey<?>> extraAttributes() {
- [
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
+ Set<AttributeKey<?>> extra = [
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_TARGET,
]
+ super.httpAttributes(uri) + extra
}
// compilation fails with @Override annotation on this method (groovy quirk?)

MODIFY
instrumentation/armeria-1.3/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_3/AbstractArmeriaHttpClientTest.groovy
instrumentation/armeria-1.3/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_3/AbstractArmeriaHttpClientTest.groovy
@@ -64,13 +64,14 @@ abstract class AbstractArmeriaHttpClientTest extends HttpClientTest<HttpRequest>
}
@Override
- List<AttributeKey<?>> extraAttributes() {
- [
+ 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
}
}

MODIFY
instrumentation/java-http-client/javaagent/src/test/groovy/JdkHttpClientTest.groovy
instrumentation/java-http-client/javaagent/src/test/groovy/JdkHttpClientTest.groovy
@@ -76,7 +76,7 @@ class JdkHttpClientTest extends HttpClientTest<HttpRequest> implements AgentTest
then:
responseCode == 200
assertTraces(1) {
- trace(0, 1 + extraClientSpans()) {
+ trace(0, 1) {
span(0) {
hasNoParent()
name expectedOperationName(method)

MODIFY
instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ClientTest.groovy
instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ClientTest.groovy
@@ -9,6 +9,7 @@ import com.ning.http.client.AsyncHttpClientConfig
import com.ning.http.client.Request
import com.ning.http.client.RequestBuilder
import com.ning.http.client.Response
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest
@@ -108,15 +109,14 @@ class Netty38ClientTest extends HttpClientTest<Request> implements AgentTestTrai
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
@Override

MODIFY
instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ClientTest.groovy
instrumentation/netty/netty-4.0/javaagent/src/test/groovy/Netty40ClientTest.groovy
@@ -18,6 +18,7 @@ import io.netty.handler.codec.http.HttpClientCodec
import io.netty.handler.codec.http.HttpHeaders
import io.netty.handler.codec.http.HttpMethod
import io.netty.handler.codec.http.HttpVersion
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest
import java.util.concurrent.CompletableFuture
@@ -92,15 +93,14 @@ class Netty40ClientTest extends HttpClientTest<DefaultFullHttpRequest> implement
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
@Override

MODIFY
instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ClientTest.groovy
instrumentation/netty/netty-4.1/javaagent/src/test/groovy/Netty41ClientTest.groovy
@@ -25,6 +25,7 @@ import io.netty.handler.codec.http.HttpClientCodec
import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpMethod
import io.netty.handler.codec.http.HttpVersion
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpClientTest
import io.opentelemetry.instrumentation.test.base.SingleConnection
@@ -110,15 +111,14 @@ class Netty41ClientTest extends HttpClientTest<DefaultFullHttpRequest> implement
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
@Override

MODIFY
instrumentation/ratpack-1.4/javaagent/src/test/groovy/client/RatpackHttpClientTest.groovy
instrumentation/ratpack-1.4/javaagent/src/test/groovy/client/RatpackHttpClientTest.groovy
package client
import io.netty.channel.ConnectTimeoutException
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.asserts.SpanAssert
import io.opentelemetry.instrumentation.test.base.HttpClientTest
@@ -130,15 +131,14 @@ class RatpackHttpClientTest extends HttpClientTest<Void> implements AgentTestTra
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
@Override

MODIFY
instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/test/groovy/AbstractReactorNettyHttpClientTest.groovy
instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/test/groovy/AbstractReactorNettyHttpClientTest.groovy
@@ -7,6 +7,7 @@ import static io.opentelemetry.instrumentation.test.utils.PortUtils.UNUSABLE_POR
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicSpan
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
@@ -84,15 +85,14 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
abstract HttpClient createHttpClient()

MODIFY
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/test/groovy/AbstractReactorNettyHttpClientTest.groovy
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/test/groovy/AbstractReactorNettyHttpClientTest.groovy
@@ -7,6 +7,7 @@ import static io.opentelemetry.instrumentation.test.utils.PortUtils.UNUSABLE_POR
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicSpan
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
+import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
@@ -84,15 +85,14 @@ abstract class AbstractReactorNettyHttpClientTest extends HttpClientTest<HttpCli
}
@Override
- boolean hasClientSpanHttpAttributes(URI uri) {
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "http://www.google.com:81/": // dropped request
case "https://192.0.2.1/": // non routable address
- return false
- default:
- return true
+ return []
}
+ return super.httpAttributes(uri)
}
abstract HttpClient createHttpClient()

MODIFY
testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpClientTest.groovy
testing-common/src/main/groovy/io/opentelemetry/instrumentation/test/base/HttpClientTest.groovy
@@ -260,8 +260,14 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
return null
}
- List<AttributeKey<?>> extraAttributes() {
- []
+ /** A list of additional HTTP client span attributes extracted by the instrumentation per URI. */
+ Set<AttributeKey<?>> httpAttributes(URI uri) {
+ [
+ SemanticAttributes.HTTP_URL,
+ SemanticAttributes.HTTP_METHOD,
+ SemanticAttributes.HTTP_FLAVOR,
+ SemanticAttributes.HTTP_USER_AGENT
+ ]
}
def "basic #method request #url"() {
@@ -271,9 +277,9 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
clientSpan(it, 0, null, method, url)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
}
}
@@ -293,10 +299,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method)
- serverSpan(it, 2 + extraClientSpans(), span(1 + extraClientSpans()))
+ serverSpan(it, 2, span(1))
}
}
@@ -345,7 +351,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
responseCode == 200
// only one trace (client).
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method)
}
@@ -371,10 +377,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
requestResult.get() == 200
// only one trace (client).
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method)
- basicSpan(it, 2 + extraClientSpans(), "child", span(0))
+ basicSpan(it, 2, "child", span(0))
}
}
@@ -396,7 +402,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
requestResult.get() == 200
// only one trace (client).
assertTraces(2) {
- trace(0, 1 + extraClientSpans()) {
+ trace(0, 1) {
clientSpan(it, 0, null, method)
}
trace(1, 1) {
@@ -422,10 +428,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
clientSpan(it, 0, null, method, uri)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
- serverSpan(it, 2 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
+ serverSpan(it, 2, span(0))
}
}
@@ -444,11 +450,11 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 4 + extraClientSpans()) {
+ trace(0, 4) {
clientSpan(it, 0, null, method, uri)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
- serverSpan(it, 2 + extraClientSpans(), span(extraClientSpans()))
- serverSpan(it, 3 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
+ serverSpan(it, 2, span(0))
+ serverSpan(it, 3, span(0))
}
}
@@ -470,11 +476,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
and:
assertTraces(1) {
- trace(0, 1 + extraClientSpans() + maxRedirects()) {
+ trace(0, 1 + maxRedirects()) {
clientSpan(it, 0, null, method, uri, responseCodeOnRedirectError(), thrownException)
- def start = 1 + extraClientSpans()
- for (int i = start; i < maxRedirects() + start; i++) {
- serverSpan(it, i, span(extraClientSpans()))
+ for (int i = 1; i < maxRedirects() + 1; i++) {
+ serverSpan(it, i, span(0))
}
}
}
@@ -495,10 +500,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
clientSpan(it, 0, null, method, uri)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
- serverSpan(it, 2 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
+ serverSpan(it, 2, span(0))
}
}
@@ -518,10 +523,10 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
basicSpan(it, 0, "parent", null)
clientSpan(it, 1, span(0), method, uri, 500)
- serverSpan(it, 2 + extraClientSpans(), span(1 + extraClientSpans()))
+ serverSpan(it, 2, span(1))
}
}
@@ -539,13 +544,13 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(2) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
clientSpan(it, 0, null, method, url)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
}
- trace(1, 2 + extraClientSpans()) {
+ trace(1, 2) {
clientSpan(it, 0, null, method, url)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
}
}
@@ -568,9 +573,9 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
clientSpan(it, 0, null, method, url)
- serverSpan(it, 1 + extraClientSpans(), span(extraClientSpans()))
+ serverSpan(it, 1, span(0))
}
}
@@ -596,7 +601,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
and:
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
basicSpan(it, 0, "parent", null, thrownException)
clientSpan(it, 1, span(0), method, uri, null, thrownException)
}
@@ -628,7 +633,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
and:
assertTraces(1) {
- trace(0, 3 + extraClientSpans()) {
+ trace(0, 3) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method, uri, null, thrownException)
basicSpan(it, 2, "callback", span(0))
@@ -654,7 +659,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
basicSpan(it, 0, "parent", null, thrownException)
clientSpan(it, 1, span(0), method, uri, null, thrownException)
}
@@ -678,7 +683,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
assertTraces(1) {
- trace(0, 2 + extraClientSpans()) {
+ trace(0, 2) {
basicSpan(it, 0, "parent", null, thrownException)
clientSpan(it, 1, span(0), method, uri, null, thrownException)
}
@@ -702,7 +707,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
then:
responseCode == 200
assertTraces(1) {
- trace(0, 1 + extraClientSpans()) {
+ trace(0, 1) {
clientSpan(it, 0, null, method, uri)
}
}
@@ -820,8 +825,7 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
// 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", URI uri = server.address.resolve("/success"), Integer responseCode = 200, Throwable exception = null, String httpFlavor = "1.1") {
def userAgent = userAgent()
- def extraAttributes = extraAttributes()
- def hasClientSpanHttpAttributes = hasClientSpanHttpAttributes(uri)
+ def httpClientAttributes = httpAttributes(uri)
trace.span(index) {
if (parentSpan == null) {
hasNoParent()
@@ -854,37 +858,44 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
} else {
"${SemanticAttributes.NET_PEER_IP.key}" { it == null || it == "127.0.0.1" || it == uri.host } // Optional
}
- if (hasClientSpanHttpAttributes) {
+
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_URL)) {
"${SemanticAttributes.HTTP_URL.key}" { it == "${uri}" || it == "${removeFragment(uri)}" }
+ }
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_METHOD)) {
"${SemanticAttributes.HTTP_METHOD.key}" method
+ }
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_FLAVOR)) {
if (uri.host == "www.google.com") {
"${SemanticAttributes.HTTP_FLAVOR.key}" { it == httpFlavor || it == "2.0" } // google https request can be http 2.0
} else {
"${SemanticAttributes.HTTP_FLAVOR.key}" httpFlavor
}
+ }
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_USER_AGENT)) {
if (userAgent) {
"${SemanticAttributes.HTTP_USER_AGENT.key}" { it.startsWith(userAgent) }
}
}
- if (responseCode) {
- "${SemanticAttributes.HTTP_STATUS_CODE.key}" responseCode
- }
-
- if (extraAttributes.contains(SemanticAttributes.HTTP_HOST)) {
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_HOST)) {
"${SemanticAttributes.HTTP_HOST}" { it == uri.host || it == "${uri.host}:${uri.port}" }
}
- if (extraAttributes.contains(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH)) {
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH)) {
"${SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH}" Long
}
- if (extraAttributes.contains(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH)) {
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH)) {
"${SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH}" Long
}
- if (extraAttributes.contains(SemanticAttributes.HTTP_SCHEME)) {
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_SCHEME)) {
"${SemanticAttributes.HTTP_SCHEME}" uri.scheme
}
- if (extraAttributes.contains(SemanticAttributes.HTTP_TARGET)) {
+ if (httpClientAttributes.contains(SemanticAttributes.HTTP_TARGET)) {
"${SemanticAttributes.HTTP_TARGET}" uri.path + "${uri.query != null ? "?${uri.query}" : ""}"
}
+
+ if (responseCode) {
+ "${SemanticAttributes.HTTP_STATUS_CODE.key}" responseCode
+ }
}
}
}
@@ -922,14 +933,6 @@ abstract class HttpClientTest<REQUEST> extends InstrumentationSpecification {
spanAssert.errorEvent(errorType, message)
}
- boolean hasClientSpanHttpAttributes(URI uri) {
- true
- }
-
- int extraClientSpans() {
- 0
- }
-
boolean testWithClientParent() {
true
}

Refactor HttpClientTest (#3159)

* Remove unused extraClientSpans() method
* Merge extraAttributes() and hasClientSpanHttpAttributes(uri) into
httpAttributes(uri): this will allow to choose extracted attributes
per URI (for example, OkHttp won't set flavor on connection exception
once it's rewritten to Instrumenter)