Invoke-GlobalNavHoldQueueResumeSmoke.ps1 4.62 KB
param(
    [string]$ApiBaseUrl = "http://localhost:5000",
    [string]$SendNextEndpointPath = "/api/internal/send-next-segment",
    [ValidateSet("GET","POST")]
    [string]$HttpMethod = "POST",
    [string]$RobotManufacturer = "HUAHENG",
    [string]$RobotSerialNumber = "1001",
    [int]$DurationSeconds = 90,
    [int]$RequestIntervalMs = 500,
    [int]$TimeoutSeconds = 8,
    [string]$LogPath = "",
    [string[]]$Patterns = @(
        "[GlobalNav] HoldEscalationCandidates",
        "[GlobalNav] ResumeMetrics",
        "ResumeDispatchTriggered",
        "queue turn pending"
    ),
    [string[]]$RequiredPatterns = @(
        "[GlobalNav] ResumeMetrics"
    )
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if ($DurationSeconds -le 0) { throw "DurationSeconds must be > 0" }
if ($RequestIntervalMs -lt 50) { throw "RequestIntervalMs must be >= 50" }

$query = "robotManufacturer=$([uri]::EscapeDataString($RobotManufacturer))&robotSerialNumber=$([uri]::EscapeDataString($RobotSerialNumber))"
$sendUri = "$ApiBaseUrl${SendNextEndpointPath}?$query"

$patternHit = @{}
foreach ($pattern in $Patterns) {
    $patternHit[$pattern] = 0
}

$requestSuccess = 0
$requestFailure = 0
$requestException = 0
$processedLogLines = 0

function Invoke-SendNextRequest {
    $params = @{
        Uri        = $sendUri
        Method     = $HttpMethod
        TimeoutSec = $TimeoutSeconds
    }

    if ($PSVersionTable.PSVersion.Major -lt 6) {
        $params["UseBasicParsing"] = $true
    }

    return Invoke-WebRequest @params
}

function Update-PatternHit {
    param(
        [string[]]$Lines
    )

    foreach ($line in $Lines) {
        foreach ($pattern in $Patterns) {
            if ($line.Contains($pattern, [StringComparison]::OrdinalIgnoreCase)) {
                $patternHit[$pattern] = [int]$patternHit[$pattern] + 1
            }
        }
    }
}

function Read-NewLogLines {
    if ([string]::IsNullOrWhiteSpace($LogPath) -or -not (Test-Path $LogPath)) {
        return @()
    }

    $all = Get-Content -Path $LogPath -ErrorAction SilentlyContinue
    if ($null -eq $all -or $all.Count -eq 0) {
        return @()
    }

    if ($processedLogLines -ge $all.Count) {
        return @()
    }

    $newLines = $all[$processedLogLines..($all.Count - 1)]
    $script:processedLogLines = $all.Count
    return $newLines
}

if (-not [string]::IsNullOrWhiteSpace($LogPath) -and (Test-Path $LogPath)) {
    $initial = Get-Content -Path $LogPath -ErrorAction SilentlyContinue
    if ($initial) {
        $processedLogLines = $initial.Count
    }
}

$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$deadline = (Get-Date).AddSeconds($DurationSeconds)

Write-Host "[GlobalNavSmoke] Start"
Write-Host "  Uri:               $sendUri"
Write-Host "  Method:            $HttpMethod"
Write-Host "  DurationSeconds:   $DurationSeconds"
Write-Host "  RequestIntervalMs: $RequestIntervalMs"
if (-not [string]::IsNullOrWhiteSpace($LogPath)) {
    Write-Host "  LogPath:           $LogPath"
}

while ((Get-Date) -lt $deadline) {
    try {
        $resp = Invoke-SendNextRequest
        if ($resp.StatusCode -ge 200 -and $resp.StatusCode -lt 300) {
            $requestSuccess++
        }
        else {
            $requestFailure++
        }
    }
    catch {
        $requestException++
    }

    $newLines = @(Read-NewLogLines)
    if ($newLines.Count -gt 0) {
        Update-PatternHit -Lines $newLines
    }

    Start-Sleep -Milliseconds $RequestIntervalMs
}

$tailLines = @(Read-NewLogLines)
if ($tailLines.Count -gt 0) {
    Update-PatternHit -Lines $tailLines
}

$stopwatch.Stop()

Write-Host ""
Write-Host "GlobalNav Hold/Queue/Resume Smoke Result"
Write-Host "  ElapsedMs:         $($stopwatch.ElapsedMilliseconds)"
Write-Host "  RequestSuccess:    $requestSuccess"
Write-Host "  RequestFailure:    $requestFailure"
Write-Host "  RequestException:  $requestException"
Write-Host ""
Write-Host "Pattern Hits:"
foreach ($pattern in $Patterns) {
    Write-Host ("  {0} => {1}" -f $pattern, $patternHit[$pattern])
}

$missingRequired = @()
foreach ($required in $RequiredPatterns) {
    if (-not $patternHit.ContainsKey($required) -or $patternHit[$required] -le 0) {
        $missingRequired += $required
    }
}

Write-Host ""
if ($missingRequired.Count -eq 0) {
    Write-Host "[GlobalNavSmoke] PASS (required patterns observed)"
}
else {
    Write-Warning ("[GlobalNavSmoke] INCOMPLETE: missing required patterns => {0}" -f ($missingRequired -join ", "))
}

Write-Host "Recommended checks:"
Write-Host "  1) Verify queue order evolves (position x/y shrinks over time)."
Write-Host "  2) Verify resume trigger appears after hold window."
Write-Host "  3) Correlate with [PathCAS] metrics under contention."