Files
aza/backup 24.2.26 - Kopie (61)/deploy/smoke_suite.ps1
2026-03-25 13:42:48 +01:00

255 lines
8.1 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
AZA Step 13: Local Sanity / Regression Smoke Suite (PowerShell 5.1 safe)
What it checks (no token leakage):
1) GET /health -> 200 and JSON {"ok": true} (or ok truthy)
2) GET /version -> 200 and JSON has "name" and "build"
3) GET /license/status WITHOUT token -> 401/403 expected
4) GET /license/status WITH token -> 200 and JSON has {valid:boolean, valid_until:number|null}
5) GET /stripe/health -> 200 if present, otherwise WARN if 404
6) GET /openapi.json -> 200 (optional, but useful)
Run (while backend is running on 127.0.0.1:8000):
powershell -ExecutionPolicy Bypass -File .\deploy\smoke_suite.ps1
Optional:
powershell -ExecutionPolicy Bypass -File .\deploy\smoke_suite.ps1 -BaseUrl http://127.0.0.1:8000
#>
[CmdletBinding()]
param(
[string]$BaseUrl = "http://127.0.0.1:8000",
[string]$EnvFile = ".\deploy\.env",
[string]$DeviceId = ""
)
function Load-DotEnv([string]$Path) {
if (-not (Test-Path -LiteralPath $Path)) {
throw "Missing .env file at: $Path"
}
$map = @{}
Get-Content -LiteralPath $Path | ForEach-Object {
$line = $_.Trim()
if ($line.Length -eq 0) { return }
if ($line.StartsWith("#")) { return }
$idx = $line.IndexOf("=")
if ($idx -lt 1) { return }
$k = $line.Substring(0, $idx).Trim()
$v = $line.Substring($idx + 1).Trim()
if (($v.StartsWith('"') -and $v.EndsWith('"')) -or ($v.StartsWith("'") -and $v.EndsWith("'"))) {
$v = $v.Substring(1, $v.Length - 2)
}
$map[$k] = $v
}
return $map
}
function All-TokensFromValue([string]$value) {
if (-not $value) { return @() }
$value = $value.Trim()
return ($value -split "[,\r\n]+" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" })
}
function Get-TokensFromEnv([hashtable]$envMap) {
if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) { return @{ src="MEDWORK_API_TOKENS"; tokens=(All-TokensFromValue $envMap["MEDWORK_API_TOKENS"]) } }
if ($envMap.ContainsKey("MEDWORK_API_TOKEN")) { return @{ src="MEDWORK_API_TOKEN"; tokens=(All-TokensFromValue $envMap["MEDWORK_API_TOKEN"]) } }
return @{ src=""; tokens=@() }
}
function Http-Get([string]$url, [hashtable]$headers = $null) {
try {
$resp = Invoke-WebRequest -Method GET -Uri $url -Headers $headers -TimeoutSec 15 -UseBasicParsing
return @{ ok=$true; status=[int]$resp.StatusCode; text=$resp.Content }
} catch {
$e = $_.Exception
$status = $null
$text = ""
if ($e.Response -and $e.Response.StatusCode) {
$status = [int]$e.Response.StatusCode
try {
$stream = $e.Response.GetResponseStream()
if ($stream) {
$reader = New-Object System.IO.StreamReader($stream)
$text = $reader.ReadToEnd()
}
} catch { }
}
return @{ ok=$false; status=$status; text=$text; message=$e.Message }
}
}
function Http-GetRest([string]$url, [hashtable]$headers) {
# Use Invoke-RestMethod for auth calls (matches authorized_test.ps1 behavior in PS5.1)
try {
$obj = Invoke-RestMethod -Method GET -Uri $url -Headers $headers -TimeoutSec 15
$txt = $obj | ConvertTo-Json -Depth 10 -Compress
return @{ ok=$true; status=200; text=$txt }
} catch {
$e = $_.Exception
$status = $null
$text = ""
if ($e.Response -and $e.Response.StatusCode) {
$status = [int]$e.Response.StatusCode
try {
$stream = $e.Response.GetResponseStream()
if ($stream) {
$reader = New-Object System.IO.StreamReader($stream)
$text = $reader.ReadToEnd()
}
} catch { }
}
return @{ ok=$false; status=$status; text=$text; message=$e.Message }
}
}
function Parse-Json([string]$s) {
try { return (ConvertFrom-Json -InputObject $s -ErrorAction Stop) } catch { return $null }
}
function Assert([bool]$cond, [string]$msg, [ref]$failCount) {
if ($cond) {
Write-Host ("PASS: " + $msg)
return $true
} else {
Write-Host ("FAIL: " + $msg)
$failCount.Value++
return $false
}
}
function Warn([string]$msg) {
Write-Host ("WARN: " + $msg)
}
function Snip([string]$s, [int]$n = 220) {
if (-not $s) { return "" }
$t = $s.Trim()
if ($t.Length -le $n) { return $t }
return ($t.Substring(0, $n) + " ...")
}
$script:lastDetails = @()
function Note-FailDetail([string]$label, $resp) {
$st = $resp.status
$tx = Snip $resp.text
$script:lastDetails += (" " + $label + ": status=" + $st + " body='" + $tx + "'")
}
$base = $BaseUrl.TrimEnd("/")
if (-not $DeviceId) {
$DeviceId = "ps-" + $env:COMPUTERNAME + "-" + $env:USERNAME
}
Write-Host "[AZA] Smoke Suite (Step 13)"
Write-Host (" BaseUrl: " + $base)
Write-Host (" EnvFile: " + $EnvFile)
Write-Host (" DeviceId: " + $DeviceId)
Write-Host ""
$fail = 0
# Load tokens (but never print them)
$envMap = $null
try { $envMap = Load-DotEnv $EnvFile } catch { $envMap = @{} }
$tk = Get-TokensFromEnv $envMap
if (-not $tk.tokens -or $tk.tokens.Count -lt 1) {
Warn "No tokens found in .env (MEDWORK_API_TOKENS / MEDWORK_API_TOKEN). Authorized checks will fail."
}
# 1) /health
$r = Http-Get "$base/health"
$health200 = ($r.status -eq 200)
if (-not $health200) { Note-FailDetail "/health" $r }
Assert ($health200) "GET /health returns 200" ([ref]$fail) | Out-Null
if ($health200) {
$j = Parse-Json $r.text
if (-not $j) {
Warn "GET /health did not parse as JSON (still OK if your health is plain text)."
} elseif ($j.PSObject.Properties.Name -contains "ok") {
if (-not ($j.ok -eq $true -or $j.ok -eq 1)) {
Warn "GET /health JSON has field ok, but it is not true."
}
}
}
Write-Host ""
# 2) /version
$r = Http-Get "$base/version"
$versionOk = $false
if ($r.status -eq 200) {
$j = Parse-Json $r.text
if ($j -and $j.name -and $j.build -ne $null) { $versionOk = $true }
}
if (-not $versionOk) { Note-FailDetail "/version" $r }
Assert ($versionOk) "GET /version returns 200 with fields {name, build}" ([ref]$fail) | Out-Null
Write-Host ""
# 3) /license/status without token should be 401/403
$r = Http-Get "$base/license/status"
$unauthOk = ($r.status -eq 401 -or $r.status -eq 403)
Assert ($unauthOk) "GET /license/status without token returns 401/403" ([ref]$fail) | Out-Null
Write-Host ""
# 4) /license/status with token should be 200 with stable schema
$authOk = $false
$lastAuthResp = $null
if ($tk.tokens -and $tk.tokens.Count -gt 0) {
foreach ($t in $tk.tokens) {
$h = @{
"X-API-Token" = $t
"X-Device-Id" = $DeviceId
"Accept" = "application/json"
}
$r = Http-GetRest "$base/license/status" $h
$lastAuthResp = $r
if ($r.status -eq 200) {
$j = Parse-Json $r.text
if ($j -and ($j.valid -is [bool]) -and ($j.PSObject.Properties.Name -contains "valid_until")) {
$vu = $j.valid_until
$vuOk = ($vu -eq $null) -or ($vu -is [int]) -or ($vu -is [long]) -or ($vu -is [double])
if ($vuOk) { $authOk = $true; break }
}
}
if ($r.status -eq 401 -or $r.status -eq 403) { continue }
if ($r.status -eq 404) { break }
}
}
if (-not $authOk -and $lastAuthResp) { Note-FailDetail "/license/status (auth)" $lastAuthResp }
Assert ($authOk) "GET /license/status with token returns 200 and schema {valid, valid_until}" ([ref]$fail) | Out-Null
Write-Host ""
# 5) /stripe/health (optional: warn on 404)
$r = Http-Get "$base/stripe/health"
if ($r.status -eq 200) {
Write-Host "PASS: GET /stripe/health returns 200"
} elseif ($r.status -eq 404) {
Warn "GET /stripe/health returned 404 (endpoint not present in this build)"
} else {
Assert $false ("GET /stripe/health returns 200 (or 404 if not included), got " + $r.status) ([ref]$fail) | Out-Null
}
Write-Host ""
# 6) /openapi.json (optional but useful)
$r = Http-Get "$base/openapi.json"
if ($r.status -eq 200) {
Write-Host "PASS: GET /openapi.json returns 200"
} elseif ($r.status -eq 404) {
Warn "GET /openapi.json returned 404"
} else {
Warn ("GET /openapi.json unexpected status: " + $r.status)
}
Write-Host ""
if ($fail -eq 0) {
Write-Host "RESULT: PASS (Step 13 smoke suite)"
exit 0
} else {
Write-Host ("RESULT: FAIL (" + $fail + " failing check(s))")
if ($script:lastDetails.Count -gt 0) {
Write-Host "Failure details (status + short body snippet):"
$script:lastDetails | ForEach-Object { Write-Host $_ }
}
exit 1
}