<# .SYNOPSIS Runs the headless automation tests (no window, no renderer) and prints one line per test. .DESCRIPTION UnrealEditor-Cmd.exe with -nullrhi runs `Automation RunTests `, writes the JSON report to Saved\Automation\Reports\index.json and exits when the queue is empty. Test names all start with "Descent." Log of the run: Saved\Logs\run_tests_last.log .EXAMPLE powershell -NoProfile -ExecutionPolicy Bypass -File Tools\run_tests.ps1 powershell -NoProfile -ExecutionPolicy Bypass -File Tools\run_tests.ps1 -Filter Descent.Kazah Exit code 0 = PASS (at least one test ran and none failed), 1 = FAIL. #> [CmdletBinding()] param( [string]$Filter = 'Descent', [int]$TimeoutSec = 300 ) $ErrorActionPreference = 'Stop' $ProjectRoot = Split-Path -Parent $PSScriptRoot $Uproject = Join-Path $ProjectRoot 'TheDescent.uproject' $EditorCmd = 'E:\Tools\UE_5.8\Engine\Binaries\Win64\UnrealEditor-Cmd.exe' $ReportDir = Join-Path $ProjectRoot 'Saved\Automation\Reports' $LogFile = Join-Path $ProjectRoot 'Saved\Logs\run_tests_last.log' if (-not (Test-Path $EditorCmd)) { Write-Host "TESTS FAIL: $EditorCmd not found"; exit 1 } New-Item -ItemType Directory -Force -Path (Split-Path $LogFile) | Out-Null if (Test-Path $ReportDir) { Remove-Item $ReportDir -Recurse -Force } New-Item -ItemType Directory -Force -Path $ReportDir | Out-Null $env:UE_SDKS_ROOT = 'D:\HADAL - The Descent\.tools\AutoSDK' $argList = @( ('"' + $Uproject + '"'), ('-ExecCmds="Automation RunTests ' + $Filter + '"'), '-TestExit="Automation Test Queue Empty"', ('-ReportExportPath="' + $ReportDir + '"'), '-nullrhi', '-unattended', '-nopause', '-nosplash', '-nosound', '-NoLiveCoding', ('-abslog="' + $LogFile + '"') ) $sw = [System.Diagnostics.Stopwatch]::StartNew() $proc = Start-Process -FilePath $EditorCmd -ArgumentList $argList -PassThru -WindowStyle Hidden $timedOut = $false if (-not $proc.WaitForExit($TimeoutSec * 1000)) { $timedOut = $true Write-Host ("time limit reached, stopping process {0} (the one this script started)" -f $proc.Id) & taskkill.exe /PID $proc.Id /T /F | Out-Null [void]$proc.WaitForExit(15000) } $sw.Stop() $exitCode = if ($proc.HasExited) { $proc.ExitCode } else { -1 } $indexPath = Join-Path $ReportDir 'index.json' $secs = [math]::Round($sw.Elapsed.TotalSeconds, 1) if (-not (Test-Path $indexPath)) { Write-Host ("TESTS FAIL no report was written ({0}); exit={1} {2}s log={3}" -f $(if ($timedOut) { 'timed out' } else { 'the run ended early' }), $exitCode, $secs, $LogFile) exit 1 } $report = Get-Content $indexPath -Raw | ConvertFrom-Json $tests = @($report.tests) $failed = 0 foreach ($t in $tests) { $ok = ($t.state -eq 'Success') if (-not $ok) { $failed++ } $label = if ($ok) { 'PASS' } else { 'FAIL' } Write-Host (" {0} {1} ({2}s)" -f $label, $t.fullTestPath, [math]::Round([double]$t.duration, 3)) if (-not $ok) { foreach ($e in @($t.entries)) { if ($e.event.type -in 'Error', 'Warning') { Write-Host (" {0}: {1}" -f $e.event.type, $e.event.message) } } } } if ($tests.Count -eq 0) { Write-Host ("TESTS FAIL the filter '{0}' matched no tests {1}s" -f $Filter, $secs); exit 1 } if ($failed -eq 0 -and $exitCode -eq 0) { Write-Host ("TESTS PASS {0} tests {1}s" -f $tests.Count, $secs) exit 0 } Write-Host ("TESTS FAIL {0} of {1} failed exit={2} {3}s log={4}" -f $failed, $tests.Count, $exitCode, $secs, $LogFile) exit 1