test: run shared live sidecar sdk corpus #101
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ci | |
| on: | |
| push: | |
| pull_request: | |
| permissions: | |
| contents: read | |
| jobs: | |
| contract: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.9" | |
| - name: Verify OpenAPI-generated contract and release projections | |
| run: python tools/generate_contract.py --check | |
| - name: Test contract authority consistency guards | |
| run: python -m unittest tools.test_generate_contract | |
| test: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| go: ["1.24.x", "1.26.x"] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ matrix.go }} | |
| cache: true | |
| - name: Check formatting | |
| run: test -z "$(gofmt -l .)" | |
| - name: Vet | |
| run: go vet ./... | |
| - name: Test accelerated-year File Store lifecycle | |
| run: go test ./runtime -run '^TestAcceleratedYearSession$' -count=1 | |
| - name: Test with race detector | |
| shell: bash | |
| run: | | |
| set +e | |
| output="$(go test -race ./... 2>&1)" | |
| status=$? | |
| printf '%s\n' "$output" | |
| if [ "$status" -ne 0 ]; then | |
| escaped="${output//'%'/'%25'}" | |
| escaped="${escaped//$'\r'/'%0D'}" | |
| escaped="${escaped//$'\n'/'%0A'}" | |
| printf '::error title=Go race detector::%s\n' "$escaped" | |
| fi | |
| exit "$status" | |
| build: | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - name: Build | |
| env: | |
| CGO_ENABLED: "0" | |
| run: go build -trimpath ./cmd/rin | |
| - name: Parse Windows Sidecar launcher | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $tokens = $null | |
| $errors = $null | |
| [void][System.Management.Automation.Language.Parser]::ParseFile( | |
| (Resolve-Path tools/start-rin.ps1), | |
| [ref]$tokens, | |
| [ref]$errors) | |
| if ($errors.Count -ne 0) { throw ($errors -join [Environment]::NewLine) } | |
| - name: Test bundled File Store, Sidecar lifecycle, and Host scaffolding | |
| shell: bash | |
| env: | |
| CGO_ENABLED: "0" | |
| run: | | |
| set +e | |
| output="$(go test ./store ./cmd/rin ./internal/hostscaffold 2>&1)" | |
| status=$? | |
| printf '%s\n' "$output" | |
| if [ "$status" -ne 0 ]; then | |
| escaped="${output//'%'/'%25'}" | |
| escaped="${escaped//$'\r'/'%0D'}" | |
| escaped="${escaped//$'\n'/'%0A'}" | |
| printf '::error title=File Store and Sidecar lifecycle tests::%s\n' "$escaped" | |
| fi | |
| exit "$status" | |
| native-host: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Configure portable C99 Host reference | |
| run: cmake -S examples/native-host -B .cache/native-host-build | |
| - name: Build with platform compiler warnings as errors | |
| run: cmake --build .cache/native-host-build --config Release | |
| - name: Run native Host scenarios | |
| run: ctest --test-dir .cache/native-host-build -C Release --output-on-failure | |
| open-spiel-reference: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| cache: pip | |
| cache-dependency-path: tools/open_spiel_requirements.txt | |
| - name: Install SHA-256-pinned OpenSpiel without optional dependencies | |
| run: >- | |
| python -m pip install --disable-pip-version-check --no-deps | |
| --require-hashes -r tools/open_spiel_requirements.txt | |
| - name: Verify sequential, simultaneous, chance, and hidden-information semantics | |
| run: python tools/verify_open_spiel.py | |
| unreal-host: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.9" | |
| - name: Verify Unreal Runtime Plugin structure and safety boundary | |
| run: python -m unittest tools.test_verify_unreal | |
| - name: Verify checked-in Unreal Runtime Plugin | |
| run: python tools/verify_unreal.py | |
| sdk-python: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python: ["3.9", "3.x"] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Test Python SDK | |
| run: python -m unittest discover -s sdk/python/tests -p 'test_*.py' | |
| - name: Test Ren'Py adapter | |
| run: python -m unittest discover -s adapters/renpy -p 'test_*.py' | |
| sdk-javascript: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| node: ["18", "24"] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| package-manager-cache: false | |
| - name: Test JavaScript SDK | |
| working-directory: sdk/javascript | |
| run: node --test | |
| terminal-story: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "18" | |
| package-manager-cache: false | |
| - name: Install the playable JavaScript slice | |
| working-directory: examples/terminal-story | |
| run: npm ci --ignore-scripts --offline | |
| - name: Test safe workflow and fallback boundaries | |
| working-directory: examples/terminal-story | |
| run: node --test | |
| - name: Prepare Sidecar output directory | |
| run: | | |
| node -e "require('fs').mkdirSync('bin', { recursive: true })" | |
| - name: Build Sidecar for the playable slice | |
| if: runner.os != 'Windows' | |
| run: go build -trimpath -o bin/rin ./cmd/rin | |
| - name: Build Sidecar for the playable slice on Windows | |
| if: runner.os == 'Windows' | |
| run: go build -trimpath -o bin/rin.exe ./cmd/rin | |
| - name: Run real-Sidecar player-value gates | |
| working-directory: examples/terminal-story | |
| run: node ./src/benchmark.js --iterations 100 | |
| sdk-java: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| java: ["17", "25"] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ matrix.java }} | |
| - name: Compile and test Java SDK | |
| run: | | |
| mkdir -p .cache/java-sdk | |
| find sdk/java/src/main/java sdk/java/test -name '*.java' > .cache/java-sdk/sources.txt | |
| javac --add-modules jdk.httpserver -d .cache/java-sdk @.cache/java-sdk/sources.txt | |
| java --add-modules jdk.httpserver -cp .cache/java-sdk io.github.sunrioa.rin.RinClientTest | |
| fabric-mod: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: gradle/actions/wrapper-validation@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "21" | |
| cache: gradle | |
| - name: Build installable Fabric JAR and test Saved Data recovery | |
| working-directory: examples/mods/fabric-rin-npc | |
| run: ./gradlew clean build --no-daemon | |
| - name: Generate standalone Fabric scaffold | |
| run: >- | |
| go run ./cmd/rin init host --engine fabric --id ci_fabric_npc | |
| --name "CI Fabric NPC" --namespace io.github.rin_ci | |
| --output fabric-generated | |
| - name: Build generated Fabric scaffold outside the example tree | |
| working-directory: fabric-generated | |
| run: ./gradlew clean build --no-daemon | |
| bepinex-plugin: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "6.0.x" | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.9" | |
| - name: Test BepInEx packaging diagnostics | |
| shell: bash | |
| run: | | |
| set +e | |
| output="$(python -m unittest tools.test_package_bepinex 2>&1)" | |
| status=$? | |
| printf '%s\n' "$output" | |
| if [ "$status" -ne 0 ]; then | |
| escaped="${output//'%'/'%25'}" | |
| escaped="${escaped//$'\r'/'%0D'}" | |
| escaped="${escaped//$'\n'/'%0A'}" | |
| printf '::error title=BepInEx packaging diagnostics::%s\n' "$escaped" | |
| fi | |
| exit "$status" | |
| - name: Build deterministic Mono and IL2CPP install packages | |
| run: python tools/package_bepinex.py | |
| - name: Restore BepInEx restart tests from lock files | |
| working-directory: examples/mods/bepinex-rin-npc | |
| run: dotnet restore RinNpc.Core.Tests/RinNpc.Core.Tests.csproj --locked-mode | |
| - name: Test stable identity, restart, and Outcome recovery | |
| working-directory: examples/mods/bepinex-rin-npc | |
| run: >- | |
| dotnet build RinNpc.Core.Tests/RinNpc.Core.Tests.csproj --no-restore | |
| --nologo -m:1 -p:UseSharedCompilation=false -p:BuildInParallel=false | |
| - name: Execute BepInEx restart tests | |
| working-directory: examples/mods/bepinex-rin-npc | |
| run: >- | |
| dotnet exec | |
| RinNpc.Core.Tests/bin/Debug/net6.0/RinNpc.Core.Tests.dll | |
| - name: Generate standalone single-backend BepInEx scaffolds | |
| run: | | |
| go run ./cmd/rin init host --engine bepinex-mono --id ci_mono_npc --name "CI Mono NPC" --namespace io.github.rin_ci --output bepinex-mono-generated | |
| go run ./cmd/rin init host --engine bepinex-il2cpp --id ci_il2cpp_npc --name "CI IL2CPP NPC" --namespace io.github.rin_ci --output bepinex-il2cpp-generated | |
| - name: Restore generated Mono restart tests from lock files | |
| working-directory: bepinex-mono-generated | |
| run: dotnet restore CiMonoNpc.Core.Tests/CiMonoNpc.Core.Tests.csproj --locked-mode | |
| - name: Build generated Mono restart tests | |
| working-directory: bepinex-mono-generated | |
| run: >- | |
| dotnet build CiMonoNpc.Core.Tests/CiMonoNpc.Core.Tests.csproj | |
| -c Release --no-restore --nologo -m:1 | |
| -p:UseSharedCompilation=false -p:BuildInParallel=false | |
| - name: Execute generated Mono restart tests | |
| working-directory: bepinex-mono-generated | |
| run: >- | |
| dotnet exec | |
| CiMonoNpc.Core.Tests/bin/Release/net6.0/CiMonoNpc.Core.Tests.dll | |
| - name: Restore generated Mono plugin from lock files | |
| working-directory: bepinex-mono-generated | |
| run: dotnet restore CiMonoNpc.Mono/CiMonoNpc.Mono.csproj --locked-mode | |
| - name: Build generated Mono plugin | |
| working-directory: bepinex-mono-generated | |
| run: >- | |
| dotnet build CiMonoNpc.Mono/CiMonoNpc.Mono.csproj | |
| -c Release --no-restore --nologo -m:1 | |
| -p:UseSharedCompilation=false -p:BuildInParallel=false | |
| - name: Package and verify generated Mono install ZIP | |
| working-directory: bepinex-mono-generated | |
| run: | | |
| python package_bepinex.py | |
| python package_bepinex.py --verify-archive dist/ci-mono-npc-bepinex-mono-0.1.0.zip | |
| - name: Restore generated IL2CPP plugin from lock files | |
| working-directory: bepinex-il2cpp-generated | |
| run: dotnet restore CiIl2cppNpc.IL2CPP/CiIl2cppNpc.IL2CPP.csproj --locked-mode | |
| - name: Build generated IL2CPP plugin | |
| working-directory: bepinex-il2cpp-generated | |
| run: >- | |
| dotnet build CiIl2cppNpc.IL2CPP/CiIl2cppNpc.IL2CPP.csproj | |
| -c Release --no-restore --nologo -m:1 | |
| -p:UseSharedCompilation=false -p:BuildInParallel=false | |
| - name: Package and verify generated IL2CPP install ZIP | |
| working-directory: bepinex-il2cpp-generated | |
| run: | | |
| python package_bepinex.py | |
| python package_bepinex.py --verify-archive dist/ci-il2cpp-npc-bepinex-il2cpp-0.1.0.zip | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: bepinex-${{ runner.os }} | |
| path: | | |
| examples/mods/bepinex-rin-npc/dist/*.zip | |
| bepinex-mono-generated/dist/*.zip | |
| bepinex-il2cpp-generated/dist/*.zip | |
| if-no-files-found: error | |
| sdk-csharp: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| include: | |
| - dotnet: "6.0.x" | |
| framework: "net6.0" | |
| - dotnet: "10.0.x" | |
| framework: "net10.0" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ matrix.dotnet }} | |
| - name: Build and test C# SDK | |
| run: | | |
| dotnet build sdk/csharp/Rin.Client.Tests/Rin.Client.Tests.csproj \ | |
| -p:RinTargetFramework=${{ matrix.framework }} \ | |
| --nologo | |
| dotnet exec \ | |
| sdk/csharp/Rin.Client.Tests/bin/Debug/${{ matrix.framework }}/Rin.Client.Tests.dll | |
| - name: Build legacy Unity compatibility target | |
| if: matrix.framework == 'net6.0' | |
| run: >- | |
| dotnet build sdk/csharp/Rin.Client/Rin.Client.csproj | |
| -p:RinTargetFramework=netstandard2.0 --nologo | |
| sdk-lua: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - name: Update package index for Lua | |
| run: sudo apt-get update | |
| - name: Install Lua | |
| run: sudo apt-get install -y lua5.1 lua5.4 | |
| - name: Test Lua SDK on Lua 5.1 | |
| run: lua5.1 sdk/lua/test_client.lua | |
| - name: Test Lua SDK on Lua 5.4 | |
| run: lua5.4 sdk/lua/test_client.lua | |
| - name: Test Luanti restart state on Lua 5.1 | |
| run: lua5.1 examples/mods/luanti-rin-npc/test_state.lua | |
| - name: Generate standalone Luanti scaffold | |
| run: >- | |
| go run ./cmd/rin init host --engine luanti --id ci_luanti_npc | |
| --name "CI Luanti NPC" --output luanti-generated | |
| - name: Parse and test generated Luanti scaffold on Lua 5.1 and 5.4 | |
| working-directory: luanti-generated | |
| run: | | |
| luac5.1 -p init.lua | |
| luac5.1 -p state.lua | |
| luac5.1 -p rin.lua | |
| lua5.1 test_state.lua | |
| luac5.4 -p init.lua | |
| luac5.4 -p state.lua | |
| luac5.4 -p rin.lua | |
| lua5.4 test_state.lua | |
| - name: Test Luanti restart state on Lua 5.4 | |
| run: lua5.4 examples/mods/luanti-rin-npc/test_state.lua | |
| - name: Parse Luanti integration on both Lua versions | |
| run: | | |
| luac5.1 -p examples/mods/luanti-rin-npc/init.lua examples/mods/luanti-rin-npc/state.lua | |
| luac5.4 -p examples/mods/luanti-rin-npc/init.lua examples/mods/luanti-rin-npc/state.lua | |
| sdk-sidecar-corpus: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| languages: python,javascript,csharp,java,lua | |
| rin: .cache/sdk-sidecar/rin | |
| - os: windows-latest | |
| languages: python,javascript,csharp,java | |
| rin: .cache/sdk-sidecar/rin.exe | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.9" | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "18" | |
| package-manager-cache: false | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "6.0.x" | |
| - name: Install the Lua corpus runtime | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y lua5.4 | |
| - name: Build the real Sidecar | |
| run: | | |
| python -c "from pathlib import Path; Path('.cache/sdk-sidecar').mkdir(parents=True, exist_ok=True)" | |
| go build -trimpath -o "${{ matrix.rin }}" ./cmd/rin | |
| - name: Validate the shared corpus | |
| run: python -m unittest tools.test_sdk_sidecar_corpus | |
| - name: Run real-Sidecar wire and SDK cases | |
| shell: bash | |
| run: >- | |
| python tools/run_sdk_sidecar_corpus.py | |
| --rin "${{ matrix.rin }}" | |
| --languages "${{ matrix.languages }}" | |
| --lua lua5.4 | |
| luanti-reference: | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26.x" | |
| cache: true | |
| - name: Generate standalone Luanti scaffold | |
| run: >- | |
| go run ./cmd/rin init host --engine luanti --id ci_luanti_npc | |
| --name "CI Luanti NPC" --output luanti-generated | |
| - name: Download and verify Luanti 5.16.1 archive | |
| shell: pwsh | |
| run: | | |
| $url = "https://github.com/luanti-org/luanti/releases/download/5.16.1/luanti-5.16.1-win64.zip" | |
| Invoke-WebRequest -Uri $url -OutFile luanti.zip | |
| $actual = (Get-FileHash luanti.zip -Algorithm SHA256).Hash.ToLowerInvariant() | |
| if ($actual -ne "a70fd87e67cc236f250fca90e5cd30211f3e45937b107158b5367d6ee26aabb8") { | |
| throw "Luanti SHA-256 mismatch" | |
| } | |
| Expand-Archive luanti.zip -DestinationPath luanti | |
| - name: Test Luanti verifier portability | |
| run: python -m unittest tools.test_verify_luanti | |
| - name: Verify checked-in Luanti Host lifecycle | |
| run: >- | |
| python tools/verify_luanti.py | |
| --luanti luanti/luanti-5.16.1-win64/bin/luanti.exe | |
| - name: Verify generated Luanti Host lifecycle | |
| run: >- | |
| python tools/verify_luanti.py | |
| --luanti luanti/luanti-5.16.1-win64/bin/luanti.exe | |
| --mod luanti-generated | |
| godot-reference: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| archive: Godot_v4.6.3-stable_linux.x86_64.zip | |
| sha256: d0bc2113065e481c9c2c2b2c37daa4e8be3fe9e27f0ab9ab0b6096e9a37907f3 | |
| - os: windows-latest | |
| archive: Godot_v4.6.3-stable_win64.exe.zip | |
| sha256: e39986a178d585ce7ac198fb8de6ea436366dc0cc00e594810c2e3e104c04b90 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Download and verify Godot on Linux | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| curl -fL "https://github.com/godotengine/godot-builds/releases/download/4.6.3-stable/${{ matrix.archive }}" -o godot.zip | |
| echo "${{ matrix.sha256 }} godot.zip" | sha256sum -c - | |
| unzip -q godot.zip -d godot | |
| chmod +x godot/Godot_v4.6.3-stable_linux.x86_64 | |
| python tools/verify_godot.py --godot godot/Godot_v4.6.3-stable_linux.x86_64 | |
| - name: Download and verify Godot on Windows | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $url = "https://github.com/godotengine/godot-builds/releases/download/4.6.3-stable/${{ matrix.archive }}" | |
| Invoke-WebRequest -Uri $url -OutFile godot.zip | |
| $actual = (Get-FileHash godot.zip -Algorithm SHA256).Hash.ToLowerInvariant() | |
| if ($actual -ne "${{ matrix.sha256 }}") { throw "Godot SHA-256 mismatch" } | |
| Expand-Archive godot.zip -DestinationPath godot | |
| python tools/verify_godot.py --godot godot/Godot_v4.6.3-stable_win64.exe | |
| unity-package: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "6.0.x" | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Compile Unity package and test restart recovery | |
| run: python tools/verify_unity.py |