Test Windows (Game) — PR #3215 @ 0c5c7091d993875d306847bbdebf3089f06cc0dc #1
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: Test Windows (Game) | |
| run-name: >- | |
| ${{ github.event.client_payload.pr_number | |
| && format('Test Windows (Game) — PR #{0} @ {1}', github.event.client_payload.pr_number, github.event.client_payload.pr_head_sha) | |
| || (github.event.inputs.commit-sha != '' && format('Test Windows (Game) @ {0}', github.event.inputs.commit-sha)) | |
| || '' }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| build-type: | |
| description: Build | |
| default: Debug | |
| type: choice | |
| options: | |
| - Debug | |
| - Release | |
| graphics-api: | |
| description: Graphics API (blank = all) | |
| default: '' | |
| type: choice | |
| options: | |
| - '' | |
| - Direct3D11 | |
| - Direct3D12 | |
| - Vulkan | |
| test-filter: | |
| description: 'dotnet test --filter expression (blank = all tests)' | |
| type: string | |
| default: '' | |
| project: | |
| description: 'Single test .csproj path to build/test (blank = whole GPU solution filter)' | |
| type: string | |
| default: '' | |
| commit-sha: | |
| description: Commit SHA to test (default = HEAD of selected branch) | |
| type: string | |
| default: '' | |
| upload-binlog: | |
| description: Capture and upload build binlog (off by default; adds some I/O overhead) | |
| default: false | |
| type: boolean | |
| workflow_call: | |
| inputs: | |
| build-type: | |
| default: Debug | |
| type: string | |
| graphics-api: | |
| default: '' | |
| type: string | |
| test-filter: | |
| default: '' | |
| type: string | |
| project: | |
| default: '' | |
| type: string | |
| commit-sha: | |
| default: '' | |
| type: string | |
| # Internal (callers only, e.g. test-gold-gen): tolerate test failures so generating new gold | |
| # doesn't fail the run. Build failures still fail. Not exposed in the dispatch UI. | |
| tolerate-test-failures: | |
| default: false | |
| type: boolean | |
| upload-binlog: | |
| default: false | |
| type: boolean | |
| repository_dispatch: | |
| # Fired by chatops bot. Payload: { pr_number, graphics-api, dispatched_by }. | |
| types: [test-windows-game] | |
| concurrency: | |
| group: test-windows-game-${{ github.event.pull_request.number || github.event.client_payload.pr_number || github.ref }}-${{ github.event.inputs.build-type || inputs.build-type || 'Debug' }}-${{ github.event.client_payload['graphics-api'] || github.event.inputs.graphics-api || inputs.graphics-api || 'all' }} | |
| cancel-in-progress: true | |
| jobs: | |
| # | |
| # Game tests - Graphics API-dependent projects (run per API). | |
| # API-independent tests live in test-windows-game-api-neutral.yml so they run once. | |
| # | |
| Game-GraphicsApi: | |
| name: Test Game ${{ matrix.graphics-api }} (${{ github.event.inputs.build-type || inputs.build-type || 'Debug' }}) | |
| runs-on: windows-2025-vs2026 | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| graphics-api: ${{ (github.event.client_payload['graphics-api'] || github.event.inputs.graphics-api || inputs.graphics-api) != '' && fromJson(format('["{0}"]', github.event.client_payload['graphics-api'] || github.event.inputs.graphics-api || inputs.graphics-api)) || fromJson('["Direct3D11","Direct3D12","Vulkan"]') }} | |
| env: | |
| STRIDE_GRAPHICS_SOFTWARE_RENDERING: "1" | |
| STRIDE_TESTS_RENDERDOC: "error" | |
| STRIDE_MAX_PARALLELISM: "8" | |
| # Crash dump collection (covers 3 crash types) — all dumps land under TestResults/ | |
| # alongside the .trx logs and the blame-hang dumps from `dotnet test`. | |
| STRIDE_TESTS_CRASH_DUMPS: "1" # Type 1: SEHException logging + minidump via FirstChanceException | |
| STRIDE_TESTS_CRASH_DUMP_DIR: "${{ github.workspace }}\\TestResults" # Shared dump directory for all crash types | |
| DOTNET_DbgEnableMiniDump: "1" # Type 2: .NET unhandled exceptions | |
| DOTNET_DbgMiniDumpType: "4" # MiniDumpWithFullMemory | |
| DOTNET_DbgMiniDumpName: "${{ github.workspace }}\\TestResults\\dotnet_%p.dmp" # Type 2: dump path | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| submodules: true | |
| # commit-sha (workflow_dispatch/_call input) wins for explicit bisecting. Otherwise | |
| # chatops dispatch passes a PR number; check out its merge ref so we test the | |
| # post-merge state (works uniformly for same-repo and fork PRs). | |
| ref: ${{ (github.event.inputs.commit-sha != '' && github.event.inputs.commit-sha) || (inputs.commit-sha != '' && inputs.commit-sha) || (github.event.client_payload.pr_number && format('refs/pull/{0}/merge', github.event.client_payload.pr_number)) || github.ref }} | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Configure crash dumps | |
| shell: pwsh | |
| run: | | |
| # WER DontShowUI: suppress dialogs without disabling dump generation | |
| reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f | |
| # WER LocalDumps: capture native crashes (type 3) | |
| $dumpDir = "${{ github.workspace }}\TestResults" | |
| New-Item -Path $dumpDir -ItemType Directory -Force | Out-Null | |
| reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d $dumpDir /f | |
| reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f | |
| reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f | |
| - name: Install Vulkan SDK | |
| if: matrix.graphics-api == 'Vulkan' | |
| uses: jakoch/install-vulkan-sdk-action@v1 | |
| with: | |
| vulkan_version: 1.4.304.1 | |
| install_runtime: true | |
| cache: true | |
| stripdown: true | |
| - name: Register Lavapipe ICD | |
| if: matrix.graphics-api == 'Vulkan' | |
| shell: pwsh | |
| run: | | |
| # CompilerApp needs a Vulkan device at build time (Skybox asset compilation). | |
| # Runtime tests are served by the Lavapipe module initializer; this step is | |
| # only for the pre-runtime CompilerApp invocation, so we register an ICD here. | |
| # Restore first so the package is in the NuGet cache. | |
| dotnet restore build\Stride.Tests.Game.GPU.slnf -p:StrideGraphicsApis=Vulkan -p:StrideGraphicsApi=Vulkan | |
| $dll = Get-ChildItem -Recurse -Path "$env:USERPROFILE\.nuget\packages\stride.dependencies.lavapipe" -Filter vulkan_lvp.dll -ErrorAction SilentlyContinue | Where-Object { $_.DirectoryName -match 'win-x64' } | Select-Object -First 1 | |
| if ($dll) { | |
| $icdPath = Join-Path $dll.DirectoryName "lvp_icd.json" | |
| $dllPath = $dll.FullName -replace '\\', '\\\\' | |
| Set-Content -Path $icdPath -Value "{`"file_format_version`":`"1.0.0`",`"ICD`":{`"library_path`":`"$dllPath`",`"api_version`":`"1.3.0`"}}" | |
| New-Item -Path "HKLM:\SOFTWARE\Khronos\Vulkan\Drivers" -Force | Out-Null | |
| New-ItemProperty -Path "HKLM:\SOFTWARE\Khronos\Vulkan\Drivers" -Name $icdPath -Value 0 -PropertyType DWord -Force | Out-Null | |
| Write-Host "Registered Lavapipe ICD: $icdPath" | |
| } else { | |
| Write-Warning "Lavapipe DLL not found in NuGet cache" | |
| } | |
| - name: Resolve build/test target | |
| shell: pwsh | |
| run: | | |
| # `project` (a single .csproj) narrows the build+test to one suite; blank = whole GPU solution filter. | |
| $proj = "${{ github.event.inputs.project || inputs.project }}" | |
| $target = if ($proj) { $proj } else { 'build\Stride.Tests.Game.GPU.slnf' } | |
| Add-Content $env:GITHUB_ENV "STRIDE_TEST_TARGET=$target" | |
| Add-Content $env:GITHUB_ENV "STRIDE_TEST_FILTER=${{ github.event.inputs.test-filter || inputs.test-filter }}" | |
| - name: Build | |
| run: | | |
| dotnet build $env:STRIDE_TEST_TARGET ` | |
| -p:StrideTestRuntimeIdentifier=win-x64 ` | |
| -p:StrideSkipAutoPack=true ` | |
| -nr:false ` | |
| ${{ inputs.upload-binlog && '-bl:build.binlog' || '' }} ` | |
| -v:m -p:WarningLevel=0 ` | |
| -p:Configuration=${{ github.event.inputs.build-type || inputs.build-type || 'Debug' }} ` | |
| -p:StridePlatforms=Windows ` | |
| -p:StrideGraphicsApis=${{ matrix.graphics-api }} ` | |
| -p:StrideGraphicsApi=${{ matrix.graphics-api }} | |
| - name: Upload build binlog | |
| # failure() so we still get the binlog when Build dies (most useful case) | |
| if: failure() || inputs.upload-binlog | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-binlog-game-${{ matrix.graphics-api }} | |
| path: build.binlog | |
| if-no-files-found: ignore | |
| - name: Test | |
| if: success() || failure() | |
| continue-on-error: ${{ inputs.tolerate-test-failures == true }} | |
| run: | | |
| $filterArgs = if ($env:STRIDE_TEST_FILTER) { @('--filter', $env:STRIDE_TEST_FILTER) } else { @() } | |
| dotnet test $env:STRIDE_TEST_TARGET ` | |
| --no-build ` | |
| --logger:trx --results-directory TestResults ` | |
| --blame-hang-timeout 5m --blame-hang-dump-type full ` | |
| -p:Configuration=${{ github.event.inputs.build-type || inputs.build-type || 'Debug' }} ` | |
| -p:StrideGraphicsApis=${{ matrix.graphics-api }} ` | |
| -p:StrideGraphicsApi=${{ matrix.graphics-api }} ` | |
| @filterArgs ` | |
| -- RunConfiguration.MaxCpuCount=1 | |
| - name: Publish Test Report | |
| if: always() | |
| uses: phoenix-actions/test-reporting@v15 | |
| with: | |
| name: 'Test Report: Windows Game ${{ matrix.graphics-api }}' | |
| path: TestResults/*.trx | |
| reporter: dotnet-trx | |
| output-to: step-summary | |
| list-tests: 'failed' | |
| # Tolerated (gold-gen) test failures shouldn't red the run via the reporter; the Build | |
| # and Test steps still fail normally. Defaults to true for direct / PR-gate runs. | |
| fail-on-error: ${{ inputs.tolerate-test-failures != true }} | |
| - name: Collect symbols for crash analysis | |
| if: always() | |
| shell: pwsh | |
| run: | | |
| $dumpDir = "${{ github.workspace }}\TestResults" | |
| if (Get-ChildItem $dumpDir -Recurse -Filter *.dmp -ErrorAction SilentlyContinue) { | |
| $symDir = Join-Path $dumpDir "symbols" | |
| New-Item -Path $symDir -ItemType Directory -Force | Out-Null | |
| Get-ChildItem bin -Recurse -Include *.pdb,*.dll,*.exe | Copy-Item -Destination $symDir | |
| Write-Host "Collected $(( Get-ChildItem $symDir ).Count) symbol files for crash analysis" | |
| } | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-artifacts-game-${{ matrix.graphics-api }} | |
| path: tests/local/ | |
| if-no-files-found: ignore | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-game-${{ matrix.graphics-api }} | |
| path: TestResults/ | |
| if-no-files-found: ignore |