完成70%

This commit is contained in:
2026-07-24 07:56:22 +08:00
parent bb6431b319
commit c7f278fe79
92 changed files with 4741 additions and 14440 deletions
+182
View File
@@ -0,0 +1,182 @@
param(
[ValidateSet('T0', 'ALL')]
[string]$Tier = 'T0',
[string]$OutputDir = ''
)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$manifestPath = Join-Path $PSScriptRoot 'night-run.manifest.json'
$manifest = Get-Content -LiteralPath $manifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
if (-not $OutputDir) {
$OutputDir = Join-Path ([System.IO.Path]::GetTempPath()) ('jiapuapp-night-run-' + (Get-Date -Format 'yyyyMMdd-HHmmss'))
}
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
$inventory = @(
Get-ChildItem -LiteralPath $PSScriptRoot -File -Recurse |
Where-Object { $_.Extension -in '.ps1', '.js' -and $_.Name -ne 'night-run.ps1' } |
ForEach-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') } |
Sort-Object
)
$powerShellCount = @($inventory | Where-Object { $_.EndsWith('.ps1') }).Count
$nodeCount = @($inventory | Where-Object { $_.EndsWith('.js') }).Count
$newExecutableTests = $inventory.Count - $manifest.baselineInventory.powershell - $manifest.baselineInventory.node
if ($newExecutableTests -lt 0) {
throw "夜跑 inventory 少于冻结基线:actual=$($inventory.Count) baseline=$($manifest.baselineInventory.powershell + $manifest.baselineInventory.node)"
}
$expectedBlocked = @{}
foreach ($entry in @($manifest.expectedBlocked)) {
$expectedBlocked[$entry.script] = [string]$entry.marker
}
$h5ChromeRuntimeTests = @{}
foreach ($script in @($manifest.h5ChromeRuntimeTests)) {
$h5ChromeRuntimeTests[[string]$script] = $true
}
if ($Tier -eq 'T0') {
$selected = @($manifest.t0 | Sort-Object -Unique)
} else {
$selected = $inventory
}
$unknown = @($selected | Where-Object { $_ -notin $inventory })
if ($unknown.Count -gt 0) {
throw "夜跑清单引用不存在的测试:$($unknown -join '、')"
}
function Test-H5ChromeRuntime {
try {
$pages = Invoke-RestMethod -Uri 'http://127.0.0.1:9222/json/list' -TimeoutSec 2
return @($pages | Where-Object {
$_.type -eq 'page' -and $_.url -like 'http://localhost:5173*'
}).Count -gt 0
} catch {
return $false
}
}
$needsH5ChromeRuntime = @($selected | Where-Object { $h5ChromeRuntimeTests.ContainsKey($_) }).Count -gt 0
$h5ChromeRuntimeReady = -not $needsH5ChromeRuntime -or (Test-H5ChromeRuntime)
function Test-ExactLine {
param([string]$Text, [string]$Marker)
return [regex]::IsMatch($Text, "(?m)^$([regex]::Escape($Marker))`r?$")
}
function Invoke-ManagedTest {
param([string]$RelativePath)
$startedAt = Get-Date
if ($h5ChromeRuntimeTests.ContainsKey($RelativePath) -and -not $h5ChromeRuntimeReady) {
return [pscustomobject]@{
script = $RelativePath
startedAt = $startedAt.ToString('o')
finishedAt = (Get-Date).ToString('o')
durationMs = 0
exitCode = -2
checkResult = 'INFRA_ERROR'
expectedBlockedMarker = $null
infraReason = 'H5_CHROME_RUNTIME_UNAVAILABLE'
outputPath = $null
errorPath = $null
}
}
$absolutePath = Join-Path $root $RelativePath.Replace('/', '\')
$outputPath = Join-Path $OutputDir (($RelativePath -replace '[\\/]', '__') + '.stdout.txt')
$errorPath = Join-Path $OutputDir (($RelativePath -replace '[\\/]', '__') + '.stderr.txt')
$fileName = if ($RelativePath.EndsWith('.ps1')) { 'powershell.exe' } else { 'node.exe' }
$arguments = if ($RelativePath.EndsWith('.ps1')) {
@('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $absolutePath)
} else {
@($absolutePath)
}
$startInfo = [System.Diagnostics.ProcessStartInfo]::new()
$startInfo.FileName = $fileName
$startInfo.Arguments = (($arguments | ForEach-Object {
'"' + ([string]$_).Replace('"', '\"') + '"'
}) -join ' ')
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $true
$startInfo.RedirectStandardOutput = $true
$startInfo.RedirectStandardError = $true
$process = [System.Diagnostics.Process]::new()
$process.StartInfo = $startInfo
if (-not $process.Start()) {
throw "无法启动夜跑子进程:$RelativePath"
}
$standardOutputTask = $process.StandardOutput.ReadToEndAsync()
$standardErrorTask = $process.StandardError.ReadToEndAsync()
$timedOut = -not $process.WaitForExit([int]$manifest.defaultTimeoutSeconds * 1000)
if ($timedOut) {
$process.Kill()
$process.WaitForExit()
}
$exitCode = if ($timedOut) { -1 } else { [int]$process.ExitCode }
$standardOutput = $standardOutputTask.GetAwaiter().GetResult()
$standardError = $standardErrorTask.GetAwaiter().GetResult()
[System.IO.File]::WriteAllText($outputPath, $standardOutput, [System.Text.UTF8Encoding]::new($false))
[System.IO.File]::WriteAllText($errorPath, $standardError, [System.Text.UTF8Encoding]::new($false))
$text = ($standardOutput + "`n" + $standardError).Trim()
$marker = $expectedBlocked[$RelativePath]
$result = if ($timedOut) {
'INFRA_ERROR'
} elseif ($marker) {
$passMarker = $marker -replace ' BLOCKED$', ' PASS'
if ($exitCode -eq 0 -and (Test-ExactLine $text $passMarker)) { 'PASS' }
elseif ($exitCode -ne 0 -and (Test-ExactLine $text $marker)) { 'EXPECTED_BLOCKED' }
else { 'FAIL' }
} elseif ($exitCode -eq 0) {
'PASS'
} else {
'FAIL'
}
return [pscustomobject]@{
script = $RelativePath
startedAt = $startedAt.ToString('o')
finishedAt = (Get-Date).ToString('o')
durationMs = [int]((Get-Date) - $startedAt).TotalMilliseconds
exitCode = $exitCode
checkResult = $result
expectedBlockedMarker = $marker
outputPath = $outputPath
errorPath = $errorPath
}
}
$records = @()
foreach ($test in $selected) {
$record = Invoke-ManagedTest $test
$records += $record
$checkpoint = [pscustomobject]@{
baselineInventoryTests = [int]$manifest.baselineInventory.powershell + [int]$manifest.baselineInventory.node
newExecutableTests = $newExecutableTests
inventoryTests = $inventory.Count
selectedTests = $selected.Count
records = $records
}
$checkpoint | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDir 'checkpoint.json') -Encoding UTF8
Write-Output ("{0} {1} exit={2}" -f $record.checkResult, $record.script, $record.exitCode)
}
$summary = [pscustomobject]@{
baselineInventoryTests = [int]$manifest.baselineInventory.powershell + [int]$manifest.baselineInventory.node
newExecutableTests = $newExecutableTests
inventoryTests = $inventory.Count
scheduledTests = $selected.Count
executedTests = $records.Count
passTests = @($records | Where-Object checkResult -eq 'PASS').Count
failTests = @($records | Where-Object checkResult -eq 'FAIL').Count
expectedBlockedTests = @($records | Where-Object checkResult -eq 'EXPECTED_BLOCKED').Count
infraErrorTests = @($records | Where-Object checkResult -eq 'INFRA_ERROR').Count
timedOutTests = @($records | Where-Object { $_.exitCode -eq -1 }).Count
notRunScheduledTests = 0
notRunTests = $inventory.Count - $selected.Count
outputDir = $OutputDir
}
$summary | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputDir 'summary.json') -Encoding UTF8
Write-Output ('NIGHT-RUN-SUMMARY ' + ($summary | ConvertTo-Json -Compress))
if ($summary.infraErrorTests -gt 0) { exit 4 }
if ($summary.failTests -gt 0) { exit 2 }
exit 0