Skip to content

Commit 27849ca

Browse files
committed
refactor(test): migrate to logback ListAppender for log testing
- Replaced captureStderr with a Logback ListAppender-based LogCapture utility - Swapped slf4j-simple for logback-classic in kotlin-sdk-server's test dependencies - Added logback-test.xml (matching the previous simplelogger.properties levels) - Tests now assert directly on captured log events instead of relying on stderr output
1 parent 04e6725 commit 27849ca

7 files changed

Lines changed: 63 additions & 37 deletions

File tree

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mockk = "1.14.9"
2424
mokksy = "0.8.1"
2525
serialization = "1.10.0"
2626
slf4j = "2.0.17"
27+
logback = "1.5.32"
2728
junit = "5.14.3"
2829

2930
[libraries]
@@ -67,6 +68,7 @@ mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
6768
mokksy = { group = "dev.mokksy", name = "mokksy", version.ref = "mokksy" }
6869
netty-bom = { group = "io.netty", name = "netty-bom", version.ref = "netty" }
6970
slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
71+
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
7072
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
7173

7274
# Samples

kotlin-sdk-server/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ kotlin {
3939
implementation(libs.ktor.server.content.negotiation)
4040
implementation(libs.ktor.server.test.host)
4141

42-
runtimeOnly(libs.slf4j.simple)
42+
implementation(libs.logback.classic)
4343
}
4444
}
4545
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.modelcontextprotocol.kotlin.sdk.server
2+
3+
import ch.qos.logback.classic.Logger
4+
import ch.qos.logback.classic.spi.ILoggingEvent
5+
import ch.qos.logback.core.read.ListAppender
6+
import org.slf4j.LoggerFactory
7+
8+
/**
9+
* Captures log events from the given logger (and its children) using a Logback [ListAppender].
10+
*
11+
* Usage:
12+
* ```
13+
* LogCapture("io.modelcontextprotocol.kotlin.sdk.server").use { logs ->
14+
* // … code that emits log messages …
15+
* logs.messages.shouldExist { "expected text" in it }
16+
* }
17+
* ```
18+
*/
19+
internal class LogCapture(loggerName: String) : AutoCloseable {
20+
private val logger: Logger = LoggerFactory.getLogger(loggerName) as Logger
21+
private val appender: ListAppender<ILoggingEvent> = ListAppender()
22+
23+
init {
24+
appender.start()
25+
logger.addAppender(appender)
26+
}
27+
28+
val messages: List<String>
29+
get() = appender.list.map { it.formattedMessage }
30+
31+
override fun close() {
32+
logger.detachAppender(appender)
33+
appender.stop()
34+
}
35+
}
Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.modelcontextprotocol.kotlin.sdk.server
22

3-
import io.kotest.matchers.string.shouldContain
4-
import io.kotest.matchers.string.shouldNotBeEmpty
3+
import io.kotest.matchers.collections.shouldExist
54
import io.ktor.client.request.get
65
import io.ktor.serialization.kotlinx.json.json
76
import io.ktor.server.application.install
@@ -11,16 +10,18 @@ import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
1110
import kotlin.test.Test
1211
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation as ServerContentNegotiation
1312

13+
private const val MCP_SERVER_PACKAGE = "io.modelcontextprotocol.kotlin.sdk.server"
14+
1415
class StreamableHttpServerConfigurationTest {
1516

16-
private fun testServer() = Server(
17+
private fun testServer(): Server = Server(
1718
Implementation("test-server", "1.0"),
1819
ServerOptions(capabilities = ServerCapabilities()),
1920
)
2021

2122
@Test
2223
fun `mcpStreamableHttp warns when ContentNegotiation is pre-installed`() {
23-
val logOutput = captureStderr {
24+
LogCapture(MCP_SERVER_PACKAGE).use { logs ->
2425
testApplication {
2526
application {
2627
install(ServerContentNegotiation) {
@@ -30,14 +31,13 @@ class StreamableHttpServerConfigurationTest {
3031
}
3132
client.get("/mcp")
3233
}
34+
logs.messages.shouldExist { "already installed with an unknown JSON configuration" in it }
3335
}
34-
35-
logOutput shouldContain "already installed with an unknown JSON configuration"
3636
}
3737

3838
@Test
3939
fun `mcpStatelessStreamableHttp warns when ContentNegotiation is pre-installed`() {
40-
val logOutput = captureStderr {
40+
LogCapture(MCP_SERVER_PACKAGE).use { logs ->
4141
testApplication {
4242
application {
4343
install(ServerContentNegotiation) {
@@ -47,14 +47,13 @@ class StreamableHttpServerConfigurationTest {
4747
}
4848
client.get("/mcp")
4949
}
50+
logs.messages.shouldExist { "already installed with an unknown JSON configuration" in it }
5051
}
51-
52-
logOutput shouldContain "already installed with an unknown JSON configuration"
5352
}
5453

5554
@Test
5655
fun `mcp warns when ContentNegotiation is pre-installed`() {
57-
val logOutput = captureStderr {
56+
LogCapture(MCP_SERVER_PACKAGE).use { logs ->
5857
testApplication {
5958
application {
6059
install(ServerContentNegotiation) {
@@ -64,8 +63,7 @@ class StreamableHttpServerConfigurationTest {
6463
}
6564
client.get("/sse")
6665
}
66+
logs.messages.shouldExist { "already installed with an unknown JSON configuration" in it }
6767
}
68-
69-
logOutput shouldContain "already installed with an unknown JSON configuration"
7068
}
7169
}

kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/TestHelpers.kt

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<configuration>
2+
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
3+
<target>System.err</target>
4+
<encoder>
5+
<pattern>[%thread] %level %logger - %msg%n</pattern>
6+
</encoder>
7+
</appender>
8+
9+
<logger name="io.ktor.server" level="DEBUG"/>
10+
<logger name="io.modelcontextprotocol" level="DEBUG"/>
11+
12+
<root level="INFO">
13+
<appender-ref ref="STDERR"/>
14+
</root>
15+
</configuration>

kotlin-sdk-server/src/jvmTest/resources/simplelogger.properties

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)