CultLib/packages/cultmath/scripts/unity-smoke/run-unity-smoke.ps1
Meta Vens 5384d476ce CultMath smoke: fail unless Unity exited 0 and this run wrote the passing results
Stale logs are deleted before launch; the results file must be newer than the launch. All commits build (no source change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:04:06 +02:00

94 lines
5.3 KiB
PowerShell

<#
.SYNOPSIS
The release smoke for the tracked org.gamecult.cultmath Unity package: imports it into a
scratch project, compiles and dispatches a compute shader that includes the package's
CultMath.Interval.hlsl and CultMath.Affine.hlsl on a real graphics device, and proves a
deliberately broken shader is rejected.
.DESCRIPTION
Run it on a Windows machine with a GPU, alone, before tagging cultmath-unity-v*. The scratch
project is built outside the repository under -WorkRoot, references the package by a file: path,
and is deleted afterwards (-Keep leaves it). Exit 0 only when Unity exited 0, this run wrote the
results file (earlier ones are deleted before launch), and all three tests of SmokeTests.cs
passed: the C# calls, the real shader dispatched with the right output, and the broken control
shader detected.
Never add -nographics. Without a device nothing compiles, and
ShaderUtil.GetComputeShaderMessageCount reports 0 messages for a compute shader that calls an
undeclared function until FindKernel or Dispatch compiles it, so a message-count check passes a
broken shader. SmokeTests.cs compiles by FindKernel, dispatches, and reads the output back.
For a long run start it detached and poll the log, for example:
Start-Process powershell -WindowStyle Hidden -ArgumentList '-File', '<this script>', '-UnityExe', '<Unity.exe>', '-WorkRoot', '<dir>'
The script writes unity.pid and unity.log under the scratch root's logs folder (kept after the run).
.PARAMETER UnityExe
Path to Unity.exe of the editor to test with (the cut that released 0.4.0 used 6000.3.24f1).
.PARAMETER WorkRoot
Directory outside the repository for the scratch project and logs. Default: a new folder under TEMP.
.PARAMETER Keep
Keep the scratch project instead of deleting it.
#>
param(
[Parameter(Mandatory)] [string] $UnityExe,
[string] $WorkRoot = (Join-Path $env:TEMP ("cultmath-unity-smoke-" + [guid]::NewGuid().ToString('N').Substring(0, 8))),
[switch] $Keep
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $UnityExe -PathType Leaf)) { throw "UnityExe not found: $UnityExe" }
$smoke = $PSScriptRoot
$package = (Resolve-Path (Join-Path $smoke '..\..\unity\org.gamecult.cultmath')).Path
$repoRoot = (git -C $smoke rev-parse --show-toplevel).Trim()
$work = [IO.Path]::GetFullPath($WorkRoot)
if ($work.StartsWith([IO.Path]::GetFullPath($repoRoot), [StringComparison]::OrdinalIgnoreCase)) {
throw "WorkRoot must be outside the repository: $work"
}
$project = Join-Path $work 'project'
$logs = Join-Path $work 'logs'
New-Item -ItemType Directory -Force -Path $logs | Out-Null
foreach ($d in 'Packages', 'Assets\Shaders', 'Assets\Tests') { New-Item -ItemType Directory -Force -Path (Join-Path $project $d) | Out-Null }
Copy-Item -LiteralPath (Join-Path $smoke 'Good.compute'), (Join-Path $smoke 'Broken.compute') -Destination (Join-Path $project 'Assets\Shaders')
Copy-Item -LiteralPath (Join-Path $smoke 'SmokeTests.cs'), (Join-Path $smoke 'CultMath.Smoke.Tests.asmdef') -Destination (Join-Path $project 'Assets\Tests')
$packageUri = 'file:' + $package.Replace([string][char]92, '/')
$manifest = [ordered]@{
dependencies = [ordered]@{
'com.unity.test-framework' = '1.6.0'
'org.gamecult.cultmath' = $packageUri
}
}
[IO.File]::WriteAllText((Join-Path $project 'Packages\manifest.json'), ($manifest | ConvertTo-Json -Depth 4), (New-Object Text.UTF8Encoding($false)))
$log = Join-Path $logs 'unity.log'
$results = Join-Path $logs 'results.xml'
# A kept logs folder may hold an earlier run's evidence: nothing from a previous run may decide this one.
foreach ($stale in $log, $results, (Join-Path $logs 'unity.pid')) { Remove-Item -LiteralPath $stale -Force -ErrorAction SilentlyContinue }
if (Test-Path -LiteralPath $results) { throw "could not clear the previous results file: $results" }
$unityArgs = @('-batchmode', '-projectPath', $project, '-runTests', '-testPlatform', 'EditMode',
'-testResults', $results, '-logFile', $log)
$launched = Get-Date
$p = Start-Process -PassThru -FilePath $UnityExe -ArgumentList $unityArgs -WindowStyle Hidden
$p.Id | Out-File (Join-Path $logs 'unity.pid') -Encoding ascii
"unity pid=$($p.Id) log=$log"
$p.WaitForExit()
"unity exit=$($p.ExitCode)"
# Pass needs all of: Unity exited 0; a results file written by this run; the real shader test passed and
# the broken control test passed (it asserts that the broken shader is rejected).
$ok = $false
if ($p.ExitCode -ne 0) { "unity exited non-zero: $($p.ExitCode)" }
elseif (-not (Test-Path -LiteralPath $results)) { 'no results file from this run' }
elseif ((Get-Item -LiteralPath $results).LastWriteTime -lt $launched) { 'results file predates this run' }
else {
$cases = @(([xml](Get-Content -LiteralPath $results -Raw)).SelectNodes('//test-case'))
$cases | ForEach-Object { "{0} {1}" -f $_.result, $_.name }
$want = 'CSharpIntervalAndAffineWork', 'RealShaderCompilesAndDispatches', 'BrokenShaderIsDetected'
$passed = @($cases | Where-Object { $_.result -eq 'Passed' } | ForEach-Object { ($_.name -split '\.')[-1] })
$ok = (@($want | Where-Object { $passed -contains $_ }).Count -eq $want.Count)
}
Get-Content -LiteralPath $log -ErrorAction SilentlyContinue | Select-String -CaseSensitive -Pattern '^SMOKE ' | ForEach-Object { $_.Line }
if (-not $Keep) { Remove-Item -LiteralPath $project -Recurse -Force }
if ($ok) { 'SMOKE PASSED'; exit 0 } else { 'SMOKE FAILED'; exit 1 }