Skip to content

Commit 658b370

Browse files
authored
refactor(test): add centralized TypeScript server factory for integration tests (#477)
# refactor(test): add centralized TypeScript server factory for integration tests - Create TypeScriptServer class for managing TypeScript MCP servers - Add dedicated typescript/ directory with server infrastructure - Refactor TsTestBase to use TypeScriptServer for stdio transport - Extract TypeScript test tools (greet, multi-greet, prompts, resources) - Use npx tsx for direct execution (better performance than npm run) - Install TypeScript dependencies automatically in test setup The TypeScriptServer factory provides: - startSse(port): Start SSE transport server - startStdio(): Start STDIO transport server - stop(): Graceful server shutdown - installDependencies(): npm install automation <!-- Provide a brief summary of your changes --> ## Motivation and Context To resurrect typescript tests ## How Has This Been Tested? Locally, CI ## Breaking Changes <!-- Will users need to update their code or configurations? --> ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [x] Test fix ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [x] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [ ] I have added appropriate error handling - [ ] I have added or updated documentation as needed ## Additional context #475
1 parent 29d34b8 commit 658b370

27 files changed

Lines changed: 2848 additions & 1119 deletions

.github/workflows/build.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141

4242
- os: windows-latest
4343
job-name: "Windows Tests"
44-
gradle-tasks: "jvmTest"
44+
gradle-tasks: "jvmTest -x :integration-test:jvmTest"
4545
max-workers: 3
4646

4747
- os: macos-latest
@@ -64,6 +64,11 @@ jobs:
6464
with:
6565
node-version: 'lts/*'
6666

67+
- name: Set up Node Packages
68+
if: matrix.os == 'ubuntu-latest'
69+
working-directory: integration-test/src/jvmTest/typescript
70+
run: npm ci
71+
6772
- name: Setup Gradle
6873
uses: gradle/actions/setup-gradle@v5
6974
with:
@@ -75,7 +80,7 @@ jobs:
7580
caches
7681
notifications
7782
sdks
78-
.konan/**
83+
../.konan/**
7984
8085
- name: ${{ matrix.job-name }}
8186
run: |-
@@ -144,6 +149,11 @@ jobs:
144149
with:
145150
add-job-summary: 'always'
146151
cache-read-only: true
152+
gradle-home-cache-includes: |
153+
caches
154+
notifications
155+
sdks
156+
../.konan/**
147157
148158
- name: Download Maven Local Repository
149159
uses: actions/download-artifact@v7

.github/workflows/conformance.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,24 @@ jobs:
3131
- name: Setup Node.js
3232
uses: actions/setup-node@v6
3333
with:
34-
node-version: '24.11.1'
34+
node-version: 'lts/*'
3535

3636
- name: Setup Gradle
3737
uses: gradle/actions/setup-gradle@v5
3838
with:
3939
add-job-summary: 'always'
40-
cache-read-only: true
40+
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
41+
gradle-home-cache-includes: |
42+
caches
43+
notifications
44+
sdks
45+
../.konan/**
4146
4247
- name: Run Conformance Tests
4348
run: ./gradlew --no-daemon :conformance-test:test
4449

4550
- name: Upload Conformance Results
46-
if: ${{ !cancelled() }}
51+
if: always()
4752
uses: actions/upload-artifact@v6
4853
with:
4954
name: conformance-results

conformance-test/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ plugins {
66

77
dependencies {
88
testImplementation(project(":kotlin-sdk"))
9-
testImplementation(kotlin("test"))
109
testImplementation(project(":test-utils"))
10+
testImplementation(kotlin("test"))
1111
testImplementation(libs.kotlin.logging)
1212
testImplementation(libs.ktor.client.cio)
1313
testImplementation(libs.ktor.server.cio)

conformance-test/src/test/kotlin/io/modelcontextprotocol/kotlin/sdk/conformance/ConformanceTest.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.modelcontextprotocol.kotlin.sdk.conformance
22

33
import io.github.oshai.kotlinlogging.KotlinLogging
4+
import io.modelcontextprotocol.kotlin.test.utils.findFreePort
45
import org.junit.jupiter.api.AfterAll
56
import org.junit.jupiter.api.BeforeAll
67
import org.junit.jupiter.api.DynamicTest
@@ -10,7 +11,6 @@ import java.io.BufferedReader
1011
import java.io.InputStreamReader
1112
import java.lang.management.ManagementFactory
1213
import java.net.HttpURLConnection
13-
import java.net.ServerSocket
1414
import java.net.URI
1515
import java.util.concurrent.TimeUnit
1616
import kotlin.properties.Delegates
@@ -70,8 +70,6 @@ class ConformanceTest {
7070
private const val GRACEFUL_SHUTDOWN_SECONDS = 5L
7171
private const val FORCE_SHUTDOWN_SECONDS = 2L
7272

73-
private fun findFreePort(): Int = ServerSocket(0).use { it.localPort }
74-
7573
private fun getRuntimeClasspath(): String = ManagementFactory.getRuntimeMXBean().classPath
7674

7775
private fun getTestClasspath(): String = System.getProperty("test.classpath") ?: getRuntimeClasspath()

integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/typescript/AbstractKotlinClientTsServerTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ abstract class AbstractKotlinClientTsServerTest : TsTestBase() {
1717
protected abstract suspend fun <T> useClient(block: suspend (Client) -> T): T
1818

1919
@Test
20-
@Timeout(30, unit = TimeUnit.SECONDS)
20+
@Timeout(20, unit = TimeUnit.SECONDS)
2121
fun connectsAndPings() = runBlocking(Dispatchers.IO) {
2222
useClient { client ->
2323
assertNotNull(client, "Client should be initialized")
@@ -30,7 +30,7 @@ abstract class AbstractKotlinClientTsServerTest : TsTestBase() {
3030
}
3131

3232
@Test
33-
@Timeout(30, unit = TimeUnit.SECONDS)
33+
@Timeout(20, unit = TimeUnit.SECONDS)
3434
fun listsTools() = runBlocking(Dispatchers.IO) {
3535
useClient { client ->
3636
val result = client.listTools()
@@ -44,7 +44,7 @@ abstract class AbstractKotlinClientTsServerTest : TsTestBase() {
4444
}
4545

4646
@Test
47-
@Timeout(30, unit = TimeUnit.SECONDS)
47+
@Timeout(20, unit = TimeUnit.SECONDS)
4848
fun callGreet() = runBlocking(Dispatchers.IO) {
4949
useClient { client ->
5050
val testName = "TestUser"
@@ -59,7 +59,7 @@ abstract class AbstractKotlinClientTsServerTest : TsTestBase() {
5959
}
6060

6161
@Test
62-
@Timeout(30, unit = TimeUnit.SECONDS)
62+
@Timeout(20, unit = TimeUnit.SECONDS)
6363
fun multipleClients() = runBlocking(Dispatchers.IO) {
6464
useClient { client1 ->
6565
useClient { client2 ->

0 commit comments

Comments
 (0)