102 lines
3.6 KiB
PowerShell
102 lines
3.6 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[ValidateRange(1, 60)]
|
|
[int]$LogWindowMinutes = 5
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$PSNativeCommandUseErrorActionPreference = $true
|
|
$projectRoot = Split-Path -Parent $PSScriptRoot
|
|
Set-Location -LiteralPath $projectRoot
|
|
|
|
function Assert-HttpStatus {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$Name,
|
|
[Parameter(Mandatory)]
|
|
[string]$Uri
|
|
)
|
|
|
|
try {
|
|
$response = Invoke-WebRequest -UseBasicParsing -Uri $Uri -TimeoutSec 5
|
|
} catch {
|
|
throw "$Name is unavailable at $Uri. $($_.Exception.Message)"
|
|
}
|
|
|
|
if ($response.StatusCode -ne 200) {
|
|
throw "$Name returned HTTP $($response.StatusCode) at $Uri."
|
|
}
|
|
|
|
Write-Host "[PASS] $Name returned HTTP 200."
|
|
}
|
|
|
|
function Assert-DependencyMetrics {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$Service,
|
|
[Parameter(Mandatory)]
|
|
[string]$Uri
|
|
)
|
|
|
|
$content = (Invoke-WebRequest -UseBasicParsing -Uri $Uri -TimeoutSec 5).Content
|
|
$dependencyLines = @($content -split "`n" | Where-Object {
|
|
$_ -match '^voice_platform_dependency_up\{'
|
|
})
|
|
if ($dependencyLines.Count -eq 0) {
|
|
throw "$Service did not expose dependency health metrics."
|
|
}
|
|
|
|
$down = @($dependencyLines | Where-Object { $_ -match '\}\s+0(?:\.0+)?\s*$' })
|
|
if ($down.Count -gt 0) {
|
|
throw "$Service has unavailable dependencies:`n$($down -join "`n")"
|
|
}
|
|
|
|
Write-Host "[PASS] $Service dependencies are available ($($dependencyLines.Count) checked)."
|
|
}
|
|
|
|
$requiredServices = @(
|
|
'api',
|
|
'callbacks',
|
|
'worker',
|
|
'web',
|
|
'mock-provider',
|
|
'mock-alert-receiver',
|
|
'postgres',
|
|
'redis',
|
|
'minio',
|
|
'keycloak'
|
|
)
|
|
$runningServices = @(docker compose ps --services --status running)
|
|
$missingServices = @($requiredServices | Where-Object { $_ -notin $runningServices })
|
|
if ($missingServices.Count -gt 0) {
|
|
throw "Required services are not running: $($missingServices -join ', ')."
|
|
}
|
|
Write-Host "[PASS] All required local services are running."
|
|
|
|
Assert-HttpStatus -Name 'API readiness' -Uri 'http://127.0.0.1:58080/health/ready'
|
|
Assert-HttpStatus -Name 'Callbacks readiness' -Uri 'http://127.0.0.1:58081/health/ready'
|
|
Assert-HttpStatus -Name 'Worker readiness' -Uri 'http://127.0.0.1:58082/health/ready'
|
|
Assert-HttpStatus -Name 'Web readiness' -Uri 'http://127.0.0.1:3100/health/ready'
|
|
Assert-HttpStatus -Name 'Mock provider liveness' -Uri 'http://127.0.0.1:59200/health/live'
|
|
Assert-HttpStatus -Name 'Mock alert receiver liveness' -Uri 'http://127.0.0.1:59210/health/live'
|
|
|
|
Assert-DependencyMetrics -Service 'API' -Uri 'http://127.0.0.1:58080/metrics'
|
|
Assert-DependencyMetrics -Service 'Worker' -Uri 'http://127.0.0.1:58082/metrics'
|
|
|
|
$outboxCounts = docker compose exec -T postgres psql -U voice -d voice_platform -tAc `
|
|
"SELECT count(*) FILTER (WHERE status IN ('pending', 'processing')), count(*) FILTER (WHERE status = 'dead') FROM outbox_event;"
|
|
$outboxCounts = $outboxCounts.Trim()
|
|
if ($outboxCounts -ne '0|0') {
|
|
throw "Outbox has open/dead work: $outboxCounts."
|
|
}
|
|
Write-Host '[PASS] Outbox has no pending, processing, or dead events.'
|
|
|
|
$recentLogs = docker compose logs --since "${LogWindowMinutes}m" api callbacks worker mock-provider mock-alert-receiver 2>&1
|
|
$errorLogs = @($recentLogs | Select-String -Pattern 'panic|fatal|level[=:]error|"level":"error"' -CaseSensitive:$false)
|
|
if ($errorLogs.Count -gt 0) {
|
|
throw "Recent service logs contain errors:`n$($errorLogs -join "`n")"
|
|
}
|
|
Write-Host "[PASS] No fatal or error-level logs in the last $LogWindowMinutes minute(s)."
|
|
|
|
Write-Host 'Lightweight functional readiness check passed.'
|