Hi! :grinning: I'm trying to implement a Ktor app...
# ktor
t
Hi! 😀 I'm trying to implement a Ktor app with a test using mock external services for a different port on localhost based on Ktor docs. A Github repo is here. YouTrack Issue is here. SendData.kt
Copy code
class SendData {
    suspend fun postData(client: HttpClient): Boolean {
        @Serializable
        data class MyDataClass( val id: Int, val value: String)
        val myData = MyDataClass(id = 0, value = "some value")
        val response: HttpResponse = client.post {
            url {
                protocol = URLProtocol.HTTP
                host = "localhost:8081"
                path("myroute")
            }
            contentType(ContentType.Application.Json)
            setBody(myData)
        }
        return (response.bodyAsText() == "OK")
    }
}
SendDataTest.kt
Copy code
class SendDataTest {
    @Test
    fun testPostData() = testApplication {
        externalServices {
            val port = "8081"
            hosts(port) {
                install(io.ktor.server.plugins.contentnegotiation.ContentNegotiation) { json() }
                routing {
                    post("/myroute") {
                        call.respondText("OK", status = HttpStatusCode.OK)
                    }
                }
            }
        }
        val testClient = createClient {
            install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { json() }
        }
        val result = SendData().postData(testClient)
        assertTrue(result)
    }
}
Throws exception:
Copy code
io.ktor.server.testing.client.InvalidTestRequestException: Can not resolve request to <http://localhost:8081>. Main app runs at localhost:80, localhost:443 and external services are <http://localhost>
	at app//io.ktor.server.testing.client.DelegatingTestClientEngine.execute(DelegatingTestClientEngine.kt:56)
	at app//io.ktor.client.engine.HttpClientEngine$executeWithinCallContext$2.invokeSuspend(HttpClientEngine.kt:99)
	at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at app//kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at app//kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at app//kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Log:
Copy code
2024-03-28 07:43:46.886 [Test worker @coroutine#1] TRACE i.k.c.p.c.ContentNegotiation - Adding Accept=application header for <http://localhost:8081/myroute>
2024-03-28 07:43:46.909 [Test worker @coroutine#1] TRACE i.k.c.p.c.ContentNegotiation - Converted request body using io.ktor.serialization.kotlinx.KotlinxSerializationConverter@5bcde458 for <http://localhost:8081/myroute>
2024-03-28 07:43:46.910 [Test worker @coroutine#1] TRACE i.ktor.client.plugins.HttpPlainText - Adding Accept-Charset=UTF-8 to <http://localhost:8081/myroute>
2024-03-28 07:43:46.915 [Test worker @coroutine#1] TRACE i.k.c.plugins.defaultTransformers - Transformed with default transformers request body for <http://localhost:8081/myroute> from class io.ktor.http.content.TextContent
2024-03-28 07:43:46.953 [Test worker @coroutine#1] TRACE i.k.client.plugins.HttpCallValidator - Processing exception io.ktor.server.testing.client.InvalidTestRequestException: Can not resolve request to <http://localhost:8081>. Main app runs at localhost:80, localhost:443 and external services are <http://localhost> for request <http://localhost:8081/myroute>
What do I need to do differently? 🤔
a
To solve the problem, you need to provide the full external service URL instead of the port:
Copy code
externalServices {
    hosts("<http://localhost:8081>") {
        // ...
    }
}
thank you color 1
t
Thank you! 😀