Initial version of sipsorcery cli console app #298
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: unity-smoke-test | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - master | |
| pull_request: | |
| branches: | |
| - master | |
| jobs: | |
| smoke-test: | |
| name: Unity ${{ matrix.unityVersion }} PlayMode smoke test (Linux) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| unityVersion: | |
| - 6000.4.7f1 | |
| testMode: | |
| - playmode | |
| steps: | |
| - name: Check for Unity license secret | |
| id: license_check | |
| env: | |
| UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} | |
| UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} | |
| UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} | |
| run: | | |
| if [ -z "$UNITY_LICENSE" ] || [ -z "$UNITY_EMAIL" ] || [ -z "$UNITY_PASSWORD" ]; then | |
| echo "has_license=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning::Unity license secrets (UNITY_LICENSE + UNITY_EMAIL + UNITY_PASSWORD) are not all set; skipping Unity smoke test. See test/Unity/README.md for setup." | |
| else | |
| echo "has_license=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| lfs: false | |
| - name: Setup .NET | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Build SIPSorcery and stage Unity plugin DLLs | |
| if: steps.license_check.outputs.has_license == 'true' | |
| env: | |
| PLUGINS_DIR: test/Unity/SipSorceryUnitySmokeTest/Assets/Plugins | |
| run: | | |
| set -euo pipefail | |
| mkdir -p staging "$PLUGINS_DIR" | |
| dotnet publish src/SIPSorcery/SIPSorcery.csproj \ | |
| --configuration Release \ | |
| --framework netstandard2.1 \ | |
| --output staging | |
| # Copy DLLs into Assets/Plugins, excluding ones Unity already | |
| # provides as built-in reference assemblies (the duplicates cause | |
| # CS1703 "Multiple assemblies with equivalent identity"). | |
| unity_provided=( | |
| Microsoft.CSharp.dll | |
| ) | |
| for dll in staging/*.dll; do | |
| name=$(basename "$dll") | |
| skip=false | |
| for provided in "${unity_provided[@]}"; do | |
| if [ "$name" = "$provided" ]; then skip=true; break; fi | |
| done | |
| if [ "$skip" = "false" ]; then | |
| cp -v "$dll" "$PLUGINS_DIR/" | |
| else | |
| echo "Skipping Unity-provided $name" | |
| fi | |
| done | |
| - name: Generate plugin .meta files | |
| if: steps.license_check.outputs.has_license == 'true' | |
| env: | |
| PLUGINS_DIR: test/Unity/SipSorceryUnitySmokeTest/Assets/Plugins | |
| # Without these, Unity defaults validateReferences=true and refuses | |
| # to load plugins with unresolved transitive refs (notably | |
| # Makaretu.Dns.Multicast -> Tmds.LibC). Pre-authoring the .meta | |
| # files lets the smoke test run in a single Unity invocation. | |
| run: | | |
| set -euo pipefail | |
| for dll in "$PLUGINS_DIR"/*.dll; do | |
| meta="$dll.meta" | |
| if [ -f "$meta" ]; then continue; fi | |
| guid=$(printf "%s" "$(basename "$dll")" | md5sum | cut -c1-32) | |
| cat > "$meta" <<EOF | |
| fileFormatVersion: 2 | |
| guid: $guid | |
| PluginImporter: | |
| externalObjects: {} | |
| serializedVersion: 3 | |
| iconMap: {} | |
| executionOrder: {} | |
| defineConstraints: [] | |
| isPreloaded: 0 | |
| isOverridable: 0 | |
| isExplicitlyReferenced: 0 | |
| validateReferences: 0 | |
| platformData: | |
| Any: | |
| enabled: 1 | |
| settings: {} | |
| Editor: | |
| enabled: 1 | |
| settings: | |
| DefaultValueInitialized: true | |
| WindowsStoreApps: | |
| enabled: 0 | |
| settings: | |
| CPU: AnyCPU | |
| userData: | |
| assetBundleName: | |
| assetBundleVariant: | |
| EOF | |
| done | |
| - name: Cache Unity Library | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/cache@v4 | |
| with: | |
| path: test/Unity/SipSorceryUnitySmokeTest/Library | |
| key: Library-SipSorceryUnitySmokeTest-${{ matrix.unityVersion }}-${{ hashFiles('test/Unity/SipSorceryUnitySmokeTest/Packages/manifest.json', 'test/Unity/SipSorceryUnitySmokeTest/ProjectSettings/ProjectVersion.txt') }} | |
| restore-keys: | | |
| Library-SipSorceryUnitySmokeTest-${{ matrix.unityVersion }}- | |
| Library-SipSorceryUnitySmokeTest- | |
| - name: Run Unity ${{ matrix.testMode }} tests | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: game-ci/unity-test-runner@v4 | |
| env: | |
| UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} | |
| UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} | |
| UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} | |
| with: | |
| projectPath: test/Unity/SipSorceryUnitySmokeTest | |
| unityVersion: ${{ matrix.unityVersion }} | |
| testMode: ${{ matrix.testMode }} | |
| artifactsPath: test/Unity/SipSorceryUnitySmokeTest/artifacts | |
| githubToken: ${{ secrets.GITHUB_TOKEN }} | |
| checkName: Unity ${{ matrix.testMode }} results | |
| - name: Upload test results | |
| if: always() && steps.license_check.outputs.has_license == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: unity-test-results-${{ matrix.unityVersion }}-${{ matrix.testMode }} | |
| path: test/Unity/SipSorceryUnitySmokeTest/artifacts | |
| smoke-test-windows: | |
| # Windows-runner job that actually reproduces issue #1614 — the bug is | |
| # in Unity's Windows-shipped Mono runtime (NetworkInformation.NetworkChange | |
| # throws PlatformNotSupportedException), and the GameCI Linux container | |
| # runs Linux Mono where the same code path works. Without this job the | |
| # smoke test passes even when the bug is present. | |
| # | |
| # Manual-only: this job runs ~20 min on a cold Unity install, is flaky | |
| # against the unity-setup cache, and burns Windows runner minutes on | |
| # every PR / push. Gate it behind workflow_dispatch so it only fires | |
| # when a maintainer explicitly triggers it from the Actions tab. | |
| if: github.event_name == 'workflow_dispatch' | |
| name: Unity ${{ matrix.unityVersion }} PlayMode smoke test (Windows) | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| unityVersion: | |
| - 6000.4.7f1 | |
| steps: | |
| - name: Check for Unity license secret | |
| id: license_check | |
| shell: bash | |
| env: | |
| UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} | |
| UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} | |
| run: | | |
| if [ -z "$UNITY_EMAIL" ] || [ -z "$UNITY_PASSWORD" ]; then | |
| echo "has_license=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning::UNITY_EMAIL / UNITY_PASSWORD secrets are not set; skipping Unity Windows smoke test. See test/Unity/README.md for setup." | |
| else | |
| echo "has_license=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| lfs: false | |
| - name: Setup .NET | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Build SIPSorcery and stage Unity plugin DLLs | |
| if: steps.license_check.outputs.has_license == 'true' | |
| shell: bash | |
| env: | |
| PLUGINS_DIR: test/Unity/SipSorceryUnitySmokeTest/Assets/Plugins | |
| run: | | |
| set -euo pipefail | |
| mkdir -p staging "$PLUGINS_DIR" | |
| dotnet publish src/SIPSorcery/SIPSorcery.csproj \ | |
| --configuration Release \ | |
| --framework netstandard2.1 \ | |
| --output staging | |
| unity_provided=( | |
| Microsoft.CSharp.dll | |
| ) | |
| for dll in staging/*.dll; do | |
| name=$(basename "$dll") | |
| skip=false | |
| for provided in "${unity_provided[@]}"; do | |
| if [ "$name" = "$provided" ]; then skip=true; break; fi | |
| done | |
| if [ "$skip" = "false" ]; then | |
| cp -v "$dll" "$PLUGINS_DIR/" | |
| else | |
| echo "Skipping Unity-provided $name" | |
| fi | |
| done | |
| - name: Generate plugin .meta files | |
| if: steps.license_check.outputs.has_license == 'true' | |
| shell: bash | |
| env: | |
| PLUGINS_DIR: test/Unity/SipSorceryUnitySmokeTest/Assets/Plugins | |
| run: | | |
| set -euo pipefail | |
| for dll in "$PLUGINS_DIR"/*.dll; do | |
| meta="$dll.meta" | |
| if [ -f "$meta" ]; then continue; fi | |
| guid=$(printf "%s" "$(basename "$dll")" | md5sum | cut -c1-32) | |
| cat > "$meta" <<EOF | |
| fileFormatVersion: 2 | |
| guid: $guid | |
| PluginImporter: | |
| externalObjects: {} | |
| serializedVersion: 3 | |
| iconMap: {} | |
| executionOrder: {} | |
| defineConstraints: [] | |
| isPreloaded: 0 | |
| isOverridable: 0 | |
| isExplicitlyReferenced: 0 | |
| validateReferences: 0 | |
| platformData: | |
| Any: | |
| enabled: 1 | |
| settings: {} | |
| Editor: | |
| enabled: 1 | |
| settings: | |
| DefaultValueInitialized: true | |
| WindowsStoreApps: | |
| enabled: 0 | |
| settings: | |
| CPU: AnyCPU | |
| userData: | |
| assetBundleName: | |
| assetBundleVariant: | |
| EOF | |
| done | |
| - name: Cache Unity Library | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: actions/cache@v4 | |
| with: | |
| path: test/Unity/SipSorceryUnitySmokeTest/Library | |
| key: Library-Windows-SipSorceryUnitySmokeTest-${{ matrix.unityVersion }}-${{ hashFiles('test/Unity/SipSorceryUnitySmokeTest/Packages/manifest.json', 'test/Unity/SipSorceryUnitySmokeTest/ProjectSettings/ProjectVersion.txt') }} | |
| restore-keys: | | |
| Library-Windows-SipSorceryUnitySmokeTest-${{ matrix.unityVersion }}- | |
| Library-Windows-SipSorceryUnitySmokeTest- | |
| - name: Install Unity ${{ matrix.unityVersion }} | |
| id: unity | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: RageAgainstThePixel/unity-setup@v2 | |
| with: | |
| unity-version: ${{ matrix.unityVersion }} | |
| build-targets: StandaloneWindows64 | |
| cache-installation: true | |
| - name: Activate Unity license | |
| if: steps.license_check.outputs.has_license == 'true' | |
| uses: RageAgainstThePixel/activate-unity-license@v2 | |
| with: | |
| license: Personal | |
| username: ${{ secrets.UNITY_EMAIL }} | |
| password: ${{ secrets.UNITY_PASSWORD }} | |
| - name: Run Unity PlayMode tests | |
| if: steps.license_check.outputs.has_license == 'true' | |
| timeout-minutes: 30 | |
| shell: pwsh | |
| run: | | |
| $proj = "$env:GITHUB_WORKSPACE\test\Unity\SipSorceryUnitySmokeTest" | |
| $unity = "${{ steps.unity.outputs.unity-editor-path }}" | |
| if (-not (Test-Path $unity)) { | |
| throw "Unity editor path not found: $unity" | |
| } | |
| New-Item -ItemType Directory -Path "$proj\artifacts" -Force | Out-Null | |
| $results = "$proj\artifacts\playmode-results.xml" | |
| $log = "$proj\artifacts\playmode.log" | |
| Write-Host "Running: $unity" | |
| # Unity.exe is a Windows-subsystem app, so PowerShell's call | |
| # operator (`&`) returns immediately without waiting. Use | |
| # Start-Process -Wait -PassThru to actually block on it and | |
| # capture the exit code. | |
| $unityArgs = @( | |
| '-batchmode', | |
| '-projectPath', $proj, | |
| '-runTests', | |
| '-testPlatform', 'PlayMode', | |
| '-testResults', $results, | |
| '-logFile', $log | |
| ) | |
| $proc = Start-Process -FilePath $unity -ArgumentList $unityArgs ` | |
| -NoNewWindow -PassThru -Wait | |
| $unityExit = $proc.ExitCode | |
| Write-Host "Unity process exit code: $unityExit" | |
| if (-not (Test-Path $results)) { | |
| Write-Host "::error::No test-results.xml produced — Unity likely crashed before tests ran." | |
| if (Test-Path $log) { Get-Content $log -Tail 100 } | |
| exit 1 | |
| } | |
| [xml]$xml = Get-Content $results | |
| $run = $xml.'test-run' | |
| $passed = [int]$run.passed | |
| $failed = [int]$run.failed | |
| $total = [int]$run.total | |
| Write-Host "Results: total=$total passed=$passed failed=$failed result=$($run.result)" | |
| if ($failed -gt 0) { | |
| Write-Host "::error::$failed Unity PlayMode test(s) failed" | |
| # Surface the failure messages, plus the tail of the Unity log | |
| # for diagnosis. | |
| $xml.SelectNodes("//test-case[@result='Failed']") | ForEach-Object { | |
| Write-Host "----- FAILED: $($_.fullname) -----" | |
| Write-Host $_.failure.message.InnerText | |
| Write-Host $_.failure.'stack-trace'.InnerText | |
| } | |
| exit 1 | |
| } | |
| if ($total -eq 0) { | |
| Write-Host "::error::0 tests were discovered — plugin import or compile likely failed." | |
| if (Test-Path $log) { Get-Content $log -Tail 100 } | |
| exit 1 | |
| } | |
| - name: Upload test results | |
| if: always() && steps.license_check.outputs.has_license == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: unity-test-results-windows-${{ matrix.unityVersion }}-playmode | |
| path: test/Unity/SipSorceryUnitySmokeTest/artifacts |