I've run across an unexpected behavior in our ktor...
# ktor
n
I've run across an unexpected behavior in our ktor server testing and haven't been able to find anything to help me answer whether it's expected, or a bug. We have a test for our ktor server application that looks something like this
Copy code
should("respond with 200 for valid request") {
    testApplication {
        val client = createClient { install(ContentNegotiation) { json(serviceCommonSerializer()) } }
        environment { config = ApplicationConfig("integration-test-application.conf") }
        application { install(Koin) { modules(buildKoinModule(client)) } }

        externalServices {
            hosts("<https://marketplace.com>") {
                routing { post("/v1/task/sync") { call.respond(HttpStatusCode.OK, defaultTasks()) } }
            }
        }

        val response =
            <http://client.post|client.post>("/v1/task/sync") {
                contentType(ContentType.Application.Json)
                setBody(SyncRequest())
            }

        ...
    }
}
We call an endpoint on the service under test at
POST /v1/task/sync
Thee handling of that endpoint results in our
MarketplaceServiceClient
making a request to our marketplace service that also includes a
POST /v1/task/sync
route What I would expect, is for the mocked route to be hit and return our mocked response. But what is actually happening is the `MarketplaceServiceClient`'s request seems to be ignoring the host and just matching the route path or our service under test. So we end up calling our service under test again (which thankfully fails for known reasons rather than looping). If i change the upstream call & mocked routes to any other route that doesn't match, then our mocked route is hit as expected Is this an expected behavior of the TestApplication client; that it would try to match routes first against the test application and then against any external services? and if so, is there any good way to avoid that behavior that doesn't require us to change route naming on our services?
a
Did I understand correctly that the problem occurs when there is an external service with the route
/v1/task/sync
and the server under test defines a route with the same path and method? If so, It seems to be an expected behavior if the request doesn't contain the host of the external service.
n
The request does include a host in the request that I expect to go to the externalService. But it's still being routed to the route on the service-under-test
our setup looks kind of like external services • hosts ◦
<http://external-service.com>
▪︎ routes •
POST v1/task/sync
service under test •
POST /v1/task/sync
MarketplaceServiceClient makes a request to
POST <http://external-service.com/v1/task/sync>
but ends calling the service-under-test route again if i change the external service route and the request route to something like
v2/task/sync
then it hits the mocked one as expected
a
Unfortunately, I cannot reproduce the problem with the following test:
Copy code
@Test
fun test() = testApplication {
    externalServices {
        hosts("<https://marketplace.com>") {
            routing { post("/v1/task/sync") { call.respond(HttpStatusCode.OK, "marketplace") } }
        }
    }

    application {
        routing {
            post("/v1/task/sync") { call.respond(HttpStatusCode.OK, "server") }
        }
    }

    val response = <http://client.post|client.post>("<https://marketplace.com/v1/task/sync>")
    assertEquals("marketplace", response.bodyAsText())
}
Can you please share a self-contained test to reproduce the bug?
n
Will try to put something together