Refactor SseIntegrationTest to use dynamic port assignment and simplify client/server initialization. (#212)

This commit is contained in:
Pavel Gorgulov 2025-08-04 18:41:33 +02:00 • committed by GitHub
commit 75d63c8cb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,7 +1,6 @@
package io.modelcontextprotocol.kotlin.sdk.integration package io.modelcontextprotocol.kotlin.sdk.integration
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.plugins.sse.SSE
import io.ktor.server.application.install import io.ktor.server.application.install
import io.ktor.server.cio.CIOApplicationEngine import io.ktor.server.cio.CIOApplicationEngine
import io.ktor.server.engine.EmbeddedServer import io.ktor.server.engine.EmbeddedServer
@ -20,36 +19,32 @@ import kotlinx.coroutines.withContext
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.fail import kotlin.test.fail
import io.ktor.client.engine.cio.CIO as ClientCIO import io.ktor.client.engine.cio.CIO as ClientCIO
import io.ktor.client.plugins.sse.SSE as ClientSSE
import io.ktor.server.cio.CIO as ServerCIO import io.ktor.server.cio.CIO as ServerCIO
import io.ktor.server.sse.SSE as ServerSSE
private const val URL = "127.0.0.1"
class SseIntegrationTest { class SseIntegrationTest {
@Test @Test
fun `client should be able to connect to sse server`() = runTest { fun `client should be able to connect to sse server`() = runTest {
val serverEngine = initServer() val serverEngine = initServer()
var client: Client? = null
try { try {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
assertDoesNotThrow { client = initClient() } val port = serverEngine.engine.resolvedConnectors().first().port
val client = initClient(port)
client.close()
} }
} catch (e: Exception) { } catch (e: Exception) {
fail("Failed to connect client: $e") fail("Failed to connect client: $e")
} finally { } finally {
client?.close()
// Make sure to stop the server // Make sure to stop the server
serverEngine.stopSuspend(1000, 2000) serverEngine.stopSuspend(1000, 2000)
} }
} }
private inline fun <T> assertDoesNotThrow(block: () -> T): T { private suspend fun initClient(port: Int): Client {
return try { return HttpClient(ClientCIO) { install(ClientSSE) }.mcpSse("http://$URL:$port")
block()
} catch (e: Throwable) {
fail("Expected no exception, but got: $e")
}
}
private suspend fun initClient(): Client {
return HttpClient(ClientCIO) { install(SSE) }.mcpSse("http://$URL:$PORT")
} }
private suspend fun initServer(): EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration> { private suspend fun initServer(): EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration> {
@ -58,16 +53,11 @@ class SseIntegrationTest {
ServerOptions(capabilities = ServerCapabilities()), ServerOptions(capabilities = ServerCapabilities()),
) )
return embeddedServer(ServerCIO, host = URL, port = PORT) { return embeddedServer(ServerCIO, host = URL, port = 0) {
install(io.ktor.server.sse.SSE) install(ServerSSE)
routing { routing {
mcp { server } mcp { server }
} }
}.startSuspend(wait = false) }.startSuspend(wait = false)
} }
companion object {
private const val PORT = 3001
private const val URL = "localhost"
}
} }