Migrate ktor tests to kotlin (#5571)

This commit is contained in:
Anuraag Agrawal 2022-03-14 20:03:40 +09:00 committed by GitHub
parent 046e4374bf
commit 90179a3441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 159 additions and 191 deletions

View File

@ -1,20 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.ktor.v1_0
import spock.lang.Specification
class IpAddressUtilTest extends Specification {
def "test ip address"() {
expect:
assert IpAddressUtilKt.isIpAddress("2001:0660:7401:0200:0000:0000:0edf:bdd7")
assert !IpAddressUtilKt.isIpAddress("2001:0660:7401:0200:0000:0000:0edf:bdd7:33")
assert IpAddressUtilKt.isIpAddress("127.0.0.1")
assert !IpAddressUtilKt.isIpAddress("127.0.0.1.1")
assert !IpAddressUtilKt.isIpAddress("localhost")
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.ktor.v1_0
import io.ktor.server.engine.ApplicationEngine
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.LibraryTestTrait
import io.opentelemetry.instrumentation.test.base.HttpServerTest
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.TimeUnit
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.PATH_PARAM
class KtorHttpServerTest extends HttpServerTest<ApplicationEngine> implements LibraryTestTrait {
@Override
ApplicationEngine startServer(int port) {
return TestServer.startServer(port, openTelemetry)
}
@Override
void stopServer(ApplicationEngine server) {
server.stop(0, 10, TimeUnit.SECONDS)
}
// ktor does not have a controller lifecycle so the server span ends immediately when the response is sent, which is
// before the controller span finishes.
@Override
boolean verifyServerSpanEndTime() {
return false
}
@Override
boolean testPathParam() {
true
}
@Override
Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
def attributes = super.httpAttributes(endpoint)
attributes.remove(SemanticAttributes.NET_PEER_PORT)
attributes
}
@Override
String expectedHttpRoute(ServerEndpoint endpoint) {
switch (endpoint) {
case PATH_PARAM:
return getContextPath() + "/path/{id}/param"
default:
return super.expectedHttpRoute(endpoint)
}
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.ktor.v1_0
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat
import org.junit.jupiter.api.Test
class IpAddressUtilTest {
@Test
fun `test ip address`() {
assertThat(isIpAddress("2001:0660:7401:0200:0000:0000:0edf:bdd7")).isTrue()
assertThat(isIpAddress("2001:0660:7401:0200:0000:0000:0edf:bdd7:33")).isFalse()
assertThat(isIpAddress("127.0.0.1")).isTrue()
assertThat(isIpAddress("127.0.0.1.1")).isFalse()
assertThat(isIpAddress("localhost")).isFalse()
}
}

View File

@ -0,0 +1,138 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.ktor.v1_0
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.context.Context
import io.opentelemetry.extension.kotlin.asContextElement
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import kotlinx.coroutines.withContext
import org.junit.jupiter.api.extension.RegisterExtension
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
class KtorHttpServerTest : AbstractHttpServerTest<ApplicationEngine>() {
companion object {
@JvmStatic
@RegisterExtension
val testing = HttpServerInstrumentationExtension.forLibrary()
}
override fun setupServer(): ApplicationEngine {
return embeddedServer(Netty, port = port) {
KtorTestUtil.installOpenTelemetry(this, testing.openTelemetry)
routing {
get(ServerEndpoint.SUCCESS.path) {
controller(ServerEndpoint.SUCCESS) {
call.respondText(ServerEndpoint.SUCCESS.body, status = HttpStatusCode.fromValue(ServerEndpoint.SUCCESS.status))
}
}
get(ServerEndpoint.REDIRECT.path) {
controller(ServerEndpoint.REDIRECT) {
call.respondRedirect(ServerEndpoint.REDIRECT.body)
}
}
get(ServerEndpoint.ERROR.path) {
controller(ServerEndpoint.ERROR) {
call.respondText(ServerEndpoint.ERROR.body, status = HttpStatusCode.fromValue(ServerEndpoint.ERROR.status))
}
}
get(ServerEndpoint.EXCEPTION.path) {
controller(ServerEndpoint.EXCEPTION) {
throw Exception(ServerEndpoint.EXCEPTION.body)
}
}
get("/query") {
controller(ServerEndpoint.QUERY_PARAM) {
call.respondText("some=${call.request.queryParameters["some"]}", status = HttpStatusCode.fromValue(ServerEndpoint.QUERY_PARAM.status))
}
}
get("/path/{id}/param") {
controller(ServerEndpoint.PATH_PARAM) {
call.respondText(
call.parameters["id"]
?: "",
status = HttpStatusCode.fromValue(ServerEndpoint.PATH_PARAM.status)
)
}
}
get("/child") {
controller(ServerEndpoint.INDEXED_CHILD) {
ServerEndpoint.INDEXED_CHILD.collectSpanAttributes { call.request.queryParameters[it] }
call.respondText(ServerEndpoint.INDEXED_CHILD.body, status = HttpStatusCode.fromValue(ServerEndpoint.INDEXED_CHILD.status))
}
}
get("/captureHeaders") {
controller(ServerEndpoint.CAPTURE_HEADERS) {
call.response.header("X-Test-Response", call.request.header("X-Test-Request") ?: "")
call.respondText(ServerEndpoint.CAPTURE_HEADERS.body, status = HttpStatusCode.fromValue(ServerEndpoint.CAPTURE_HEADERS.status))
}
}
}
}.start()
}
override fun stopServer(server: ApplicationEngine) {
server.stop(0, 10, TimeUnit.SECONDS)
}
// Copy in HttpServerTest.controller but make it a suspending function
private suspend fun controller(endpoint: ServerEndpoint, wrapped: suspend () -> Unit) {
assert(Span.current().spanContext.isValid, { "Controller should have a parent span. " })
if (endpoint == ServerEndpoint.NOT_FOUND) {
wrapped()
}
val span = testing.openTelemetry.getTracer("test").spanBuilder("controller").setSpanKind(SpanKind.INTERNAL).startSpan()
try {
withContext(Context.current().with(span).asContextElement()) {
wrapped()
}
span.end()
} catch (e: Exception) {
span.setStatus(StatusCode.ERROR)
span.recordException(if (e is ExecutionException) e.cause ?: e else e)
span.end()
throw e
}
}
override fun configure(options: HttpServerTestOptions) {
options.setTestPathParam(true)
options.setHttpAttributes {
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - SemanticAttributes.NET_PEER_PORT
}
options.setExpectedHttpRoute {
when (it) {
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
else -> expectedHttpRoute(it)
}
}
}
}

View File

@ -1,112 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.ktor.v1_0
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.context.Context
import io.opentelemetry.extension.kotlin.asContextElement
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.*
import kotlinx.coroutines.withContext
import java.util.concurrent.ExecutionException
class TestServer {
companion object {
private val tracer = GlobalOpenTelemetry.getTracer("test")
@JvmStatic
fun startServer(port: Int, openTelemetry: OpenTelemetry): ApplicationEngine {
return embeddedServer(Netty, port = port) {
KtorTestUtil.installOpenTelemetry(this, openTelemetry)
routing {
get(SUCCESS.path) {
controller(SUCCESS) {
call.respondText(SUCCESS.body, status = HttpStatusCode.fromValue(SUCCESS.status))
}
}
get(REDIRECT.path) {
controller(REDIRECT) {
call.respondRedirect(REDIRECT.body)
}
}
get(ERROR.path) {
controller(ERROR) {
call.respondText(ERROR.body, status = HttpStatusCode.fromValue(ERROR.status))
}
}
get(EXCEPTION.path) {
controller(EXCEPTION) {
throw Exception(EXCEPTION.body)
}
}
get("/query") {
controller(QUERY_PARAM) {
call.respondText("some=${call.request.queryParameters["some"]}", status = HttpStatusCode.fromValue(QUERY_PARAM.status))
}
}
get("/path/{id}/param") {
controller(PATH_PARAM) {
call.respondText(call.parameters["id"] ?: "", status = HttpStatusCode.fromValue(PATH_PARAM.status))
}
}
get("/child") {
controller(INDEXED_CHILD) {
INDEXED_CHILD.collectSpanAttributes { call.request.queryParameters[it] }
call.respondText(INDEXED_CHILD.body, status = HttpStatusCode.fromValue(INDEXED_CHILD.status))
}
}
get("/captureHeaders") {
controller(CAPTURE_HEADERS) {
call.response.header("X-Test-Response", call.request.header("X-Test-Request") ?: "")
call.respondText(CAPTURE_HEADERS.body, status = HttpStatusCode.fromValue(CAPTURE_HEADERS.status))
}
}
}
}.start()
}
// Copy in HttpServerTest.controller but make it a suspending function
private suspend fun controller(endpoint: ServerEndpoint, wrapped: suspend () -> Unit) {
assert(Span.current().spanContext.isValid, { "Controller should have a parent span. " })
if (endpoint == NOT_FOUND) {
wrapped()
}
val span = tracer.spanBuilder("controller").setSpanKind(SpanKind.INTERNAL).startSpan()
try {
withContext(Context.current().with(span).asContextElement()) {
wrapped()
}
span.end()
} catch (e: Exception) {
span.setStatus(StatusCode.ERROR)
span.recordException(if (e is ExecutionException) e.cause ?: e else e)
span.end()
throw e
}
}
}
}