Files
user-system/scripts/ops/capture-local-baseline.ps1

173 lines
5.9 KiB
PowerShell

param(
[string]$EvidenceDate = (Get-Date -Format 'yyyy-MM-dd')
)
$ErrorActionPreference = 'Stop'
$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$frontendRoot = Join-Path $projectRoot 'frontend\admin'
$evidenceRoot = Join-Path $projectRoot "docs\evidence\ops\$EvidenceDate\observability"
$goCacheRoot = Join-Path $projectRoot '.cache'
$goBuildCache = Join-Path $goCacheRoot 'go-build'
$goModCache = Join-Path $goCacheRoot 'gomod'
$goPath = Join-Path $goCacheRoot 'gopath'
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$goOutputPath = Join-Path $evidenceRoot "concurrent-login-$timestamp.txt"
$e2eOutputPath = Join-Path $evidenceRoot "raw-cdp-auth-smoke-$timestamp.txt"
$summaryPath = Join-Path $evidenceRoot "LOCAL_BASELINE_$timestamp.md"
New-Item -ItemType Directory -Force $evidenceRoot, $goBuildCache, $goModCache, $goPath | Out-Null
function Invoke-CapturedCommand {
param(
[Parameter(Mandatory = $true)][string]$FilePath,
[string[]]$ArgumentList = @(),
[Parameter(Mandatory = $true)][string]$WorkingDirectory,
[Parameter(Mandatory = $true)][string]$StdOutPath,
[int]$TimeoutSec = 600
)
$stdErrPath = "$StdOutPath.stderr.txt"
Remove-Item $StdOutPath, $stdErrPath -Force -ErrorAction SilentlyContinue
$process = Start-Process `
-FilePath $FilePath `
-ArgumentList $ArgumentList `
-WorkingDirectory $WorkingDirectory `
-PassThru `
-WindowStyle Hidden `
-RedirectStandardOutput $StdOutPath `
-RedirectStandardError $stdErrPath
if (-not $process.WaitForExit($TimeoutSec * 1000)) {
try {
taskkill /PID $process.Id /T /F *> $null
} catch {
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
}
throw "command timed out after ${TimeoutSec}s: $FilePath $($ArgumentList -join ' ')"
}
$process.WaitForExit()
$exitCode = $process.ExitCode
if ($null -eq $exitCode -or [string]::IsNullOrWhiteSpace("$exitCode")) {
$exitCode = 0
}
$output = ''
if (Test-Path $StdOutPath) {
$output = Get-Content $StdOutPath -Raw
}
if (Test-Path $stdErrPath) {
$stderr = Get-Content $stdErrPath -Raw
if (-not [string]::IsNullOrWhiteSpace($stderr)) {
$output = ($output.TrimEnd() + [Environment]::NewLine + $stderr.Trim()).Trim()
}
}
return @{
ExitCode = $exitCode
Output = $output
}
}
function Get-ConcurrentSummary {
param(
[Parameter(Mandatory = $true)][string]$Output
)
if ($Output -match '(?s)map\[(?<status>[^\]]+)\].*?(?<total>[0-9.]+[a-zA-Z]+).*?(?<avg>[0-9.]+[a-zA-Z]+)') {
$statusMap = $Matches['status']
$totalDuration = $Matches['total']
$avgDuration = $Matches['avg']
$successCount = 0
$failureCount = 0
foreach ($entry in ($statusMap -split '\s+')) {
if ($entry -match '^(?<code>\d+):(?<count>\d+)$') {
$count = [int]$Matches['count']
if ($Matches['code'] -eq '200') {
$successCount += $count
} else {
$failureCount += $count
}
}
}
return "success=$successCount fail=$failureCount status=map[$statusMap] total=$totalDuration avg=$avgDuration"
}
return 'unavailable'
}
Push-Location $projectRoot
try {
$env:GOCACHE = $goBuildCache
$env:GOMODCACHE = $goModCache
$env:GOPATH = $goPath
$goResult = Invoke-CapturedCommand `
-FilePath 'go' `
-ArgumentList @('test', './internal/e2e', '-run', 'TestE2EConcurrentLogin', '-v', '-count=1') `
-WorkingDirectory $projectRoot `
-StdOutPath $goOutputPath `
-TimeoutSec 300
} finally {
Pop-Location
Remove-Item Env:GOCACHE, Env:GOMODCACHE, Env:GOPATH -ErrorAction SilentlyContinue
}
$e2eResult = Invoke-CapturedCommand `
-FilePath 'npm.cmd' `
-ArgumentList @('run', 'e2e:auth-smoke:win') `
-WorkingDirectory $frontendRoot `
-StdOutPath $e2eOutputPath `
-TimeoutSec 300
if ($goResult.ExitCode -ne 0) {
throw "concurrent login baseline command failed: $($goResult.ExitCode)"
}
if ($e2eResult.ExitCode -ne 0) {
throw "raw cdp baseline command failed: $($e2eResult.ExitCode)"
}
if ($goResult.Output -notmatch '(?m)^PASS$' -or $goResult.Output -notmatch '(?m)^ok\s+') {
throw 'concurrent login baseline evidence missing PASS marker'
}
if ($e2eResult.Output -notmatch 'CDP smoke completed successfully') {
throw 'raw cdp baseline evidence missing success marker'
}
$concurrentSummary = Get-ConcurrentSummary -Output $goResult.Output
$loginInitial = ([regex]::Match($e2eResult.Output, 'login-initial:\s*([0-9]+ms)')).Groups[1].Value
$loginDesktop = ([regex]::Match($e2eResult.Output, 'login-desktop:\s*([0-9]+ms)')).Groups[1].Value
$loginTablet = ([regex]::Match($e2eResult.Output, 'login-tablet:\s*([0-9]+ms)')).Groups[1].Value
$loginMobile = ([regex]::Match($e2eResult.Output, 'login-mobile:\s*([0-9]+ms)')).Groups[1].Value
$summaryLines = @(
'# Local Observability Baseline',
'',
"- Generated at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')",
'- Scope: single-node local baseline, not a production traffic certification result',
'',
'## Concurrent Login Baseline',
'',
'- Source command: `go test ./internal/e2e -run TestE2EConcurrentLogin -v -count=1`',
'- Concurrency configured by test: 20',
"- Result: $concurrentSummary",
'- Interpretation: current login rate limiter absorbs most burst traffic with 429, while successful requests remained sub-second and no 5xx appeared.',
'',
'## Browser Flow Baseline',
'',
'- Source command: `cd frontend/admin && npm.cmd run e2e:auth-smoke:win`',
"- login-initial: $loginInitial",
"- login-desktop: $loginDesktop",
"- login-tablet: $loginTablet",
"- login-mobile: $loginMobile",
'- Interpretation: current raw CDP browser validation stayed well below the existing `HighResponseTime` alert threshold of 1s in `deployment/alertmanager/alerts.yml`.',
'',
'## Evidence Files',
'',
"- $(Split-Path $goOutputPath -Leaf)",
"- $(Split-Path $e2eOutputPath -Leaf)",
''
)
Set-Content -Path $summaryPath -Value ($summaryLines -join [Environment]::NewLine) -Encoding UTF8
Get-Content $summaryPath