kotlin-sdk/.github/workflows/build.yml
Konstantin Pavlov 6ad9bf2122
fix(integration-test): refactor integration test infrastructure, fix and enable tests with ts-client (#478)
# Refactor integration test infrastructure, fix and enable tests with
ts-client

- Refactor TypeScript integration test infrastructure to support
parallel execution and real I/O operations.
- Extract reusable TypeScriptClient component
- Migrate some tests from `runTest` to `runBlocking` for tests that
spawn actual processes and communicate over real network connections.

## Key Changes 

  - Extract `TypeScriptClient` class for managing TS client processes
- Move client scripts to integration-test/src/jvmTest/typescript/client/
- Migrate typescript: `myClient.ts`(2) → `sse-client.ts`,
`stdio-client.ts`
  - Automate TypeScript dependency installation in static initializer
  
- Enable JUnit parallel execution (dynamic strategy, concurrent mode)
with test timeout of 2 minutes
- Replace `mutableListOf` with `ConcurrentLinkedQueue` for thread-safe
notification handling
  - Migrate integration tests from `runTest` to `runBlocking`
**Rationale:** Integration tests that spawn real TypeScript processes,
establish actual
HTTP/SSE connections, and manage server lifecycles require real-time I/O
behavior. The runTest framework's virtual time is designed for fast unit
tests with simulated timing, not for integration scenarios where
external processes and network communication must occur in real time.
Parallel execution requires thread-safe data structures
(ConcurrentLinkedQueue)
to safely collect notifications from multiple concurrent test instances.

  - Add `EmbeddedServer.actualPort()` extension to get bound port
  - Standardize kotlin.time.Duration usage across test utilities
  - Update processUtils.stopProcess() to accept Duration parameter
  - Replace RuntimeException checks with idiomatic check() calls
  - Revert `--rerun-tasks` flag to Gradle workflows for reliable builds

## Motivation and Context

Integration tests with typescript client are now broken. Enabling
parallel test execution will force writing thread-safe independent tests
and will highlight problems faster.

## How Has This Been Tested?
CI

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] CI Update
- [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
Follow up for #477
2026-01-11 09:38:13 +02:00

179 lines
5.2 KiB
YAML

name: Build
on:
workflow_dispatch:
pull_request:
branches: [ main ]
push:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
# Cancel only when the run is NOT on `main` branch
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
checks: write
pull-requests: write # only required if `comment: true` was enabled
env:
JAVA_VERSION: 21
JAVA_DISTRIBUTION: temurin
JAVA_OPTS: "-Dfile.encoding=UTF-8 -Djava.awt.headless=true"
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dkotlin.compiler.execution.strategy=in-process"
jobs:
build:
runs-on: ${{ matrix.os }}
name: Build (${{ matrix.job-name }})
timeout-minutes: 30
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
job-name: "Linux Tests"
gradle-tasks: "build ktlintCheck koverLog koverHtmlReport publishToMavenLocal -Pversion=1-SNAPSHOT"
max-workers: 3
- os: windows-latest
job-name: "Windows Tests"
gradle-tasks: "jvmTest -x :integration-test:jvmTest"
max-workers: 3
- os: macos-latest
job-name: "iOS Simulator tests"
gradle-tasks: "linkIosSimulatorArm64 iosSimulatorArm64Test"
max-workers: 2
steps:
- uses: actions/checkout@v6
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v5
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
- name: Set up Node.js
if: matrix.os == 'ubuntu-latest'
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
- name: Set up Node Packages
if: matrix.os == 'ubuntu-latest'
working-directory: integration-test/src/jvmTest/typescript
run: npm ci
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
with:
validate-wrappers: true
add-job-summary: 'always'
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-home-cache-includes: |
caches
notifications
sdks
../.konan/**
- name: ${{ matrix.job-name }}
run: |-
./gradlew ${{ matrix.gradle-tasks }} -x :conformance-test:test --max-workers ${{ matrix.max-workers }} --continue --rerun-tasks --configure-on-demand --parallel
- name: Upload Reports
if: always()
uses: actions/upload-artifact@v6
with:
name: reports-build-${{ matrix.os }}
path: |
**/build/reports/
- name: Publish Test Report
uses: mikepenz/action-junit-report@v6
if: always()
with:
annotate_only: true
detailed_summary: true
flaky_summary: true
group_suite: true
include_empty_in_summary: false
include_time_in_summary: true
report_paths: '**/test-results/**/TEST-*.xml'
truncate_stack_traces: false
- name: Archive Maven Local Repository
if: ${{ success() && matrix.os == 'ubuntu-latest' }}
run: |
cd ~/.m2/repository && zip -r $GITHUB_WORKSPACE/local-maven-repository.zip .
- name: Upload Maven Local Repository
if: ${{ success() && matrix.os == 'ubuntu-latest' }}
uses: actions/upload-artifact@v6
with:
name: local-maven-repository
path: local-maven-repository.zip
retention-days: 1
samples:
needs: [ build ]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sample:
- kotlin-mcp-client
- kotlin-mcp-server
- weather-stdio-server
name: "Build Sample: ${{ matrix.sample }}"
timeout-minutes: 10
env:
JAVA_OPTS: "-Xmx8g -Dfile.encoding=UTF-8 -Djava.awt.headless=true -Dkotlin.daemon.jvm.options=-Xmx6g"
steps:
- uses: actions/checkout@v6
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v5
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
with:
add-job-summary: 'always'
cache-read-only: true
gradle-home-cache-includes: |
caches
notifications
sdks
../.konan/**
- name: Download Maven Local Repository
uses: actions/download-artifact@v7
with:
name: local-maven-repository
path: .
- name: Extract Maven Local Repository
run: |
mkdir -p ~/.m2/repository
unzip -o local-maven-repository.zip -d ~/.m2/repository
- name: "Build Sample: ${{ matrix.sample }}"
working-directory: ./samples/${{ matrix.sample }}
run: ./gradlew build -Pmcp.kotlin.overrideVersion=1-SNAPSHOT --rerun-tasks
- name: Upload Reports
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v6
with:
name: reports-samples-snapshot-${{ matrix.sample }}
path: |
**/build/reports/