Migrate ktor tests to kotlin
DELETE
instrumentation/ktor-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/ktor/v1_0/IpAddressUtilTest.groovy
-/*
- * 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")
- }
-}

DELETE
instrumentation/ktor-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.groovy
-/*
- * 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)
- }
- }
-}

ADD
instrumentation/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/IpAddressUtilTest.kt
+/*
+ * 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()
+ }
+}

ADD
instrumentation/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.kt
+/*
+ * 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)
+ }
+ }
+ }
+}

DELETE
instrumentation/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/TestServer.kt
-/*
- * 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
- }
- }
- }
-}

Migrate ktor tests to kotlin (#5571)