param([switch]$KeepContainers) $ErrorActionPreference = 'Stop' $repo = (Resolve-Path (Join-Path $PSScriptRoot '../..')).Path Set-Location -LiteralPath $repo $composeArgs = @('compose', '-p', 'packmate-mcp-capacity', '-f', 'stress/network/docker-compose.yml', '-f', 'mcp/tests/compose.yml', '-f', 'mcp/tests/capacity.yml') $testerName = 'packmate-mcp-capacity-tester' $reportDir = Join-Path $repo 'build/reports/mcp' $healthProbe = @' import sys, urllib.request try: urllib.request.urlopen('http://localhost:65002/healthz', timeout=2) except Exception: sys.exit(1) '@ if (!(Test-Path -LiteralPath (Join-Path $repo 'build/libs/packmate-1.0-SNAPSHOT.jar'))) { throw 'Build the current backend with bootJar first; see docs/MCP.md.' } function Invoke-Compose { & docker @composeArgs @args if ($LASTEXITCODE -ne 0) { throw "Docker Compose failed: $args" } } $existing = & docker ps -aq --filter "name=^/$testerName`$" if ($existing) { throw "Remove the previous disposable $testerName container before running again." } New-Item -ItemType Directory -Force -Path $reportDir | Out-Null foreach ($name in @('restart-request.json', 'restart-done.json', 'capacity.json')) { $report = Join-Path $reportDir $name if (Test-Path -LiteralPath $report) { Remove-Item -LiteralPath $report } } try { Invoke-Compose up --no-build -d db target packmate mcp Invoke-Compose run -d --no-deps --name $testerName tester $deadline = (Get-Date).AddMinutes(20) $restarted = $false while ((Get-Date) -lt $deadline) { if (!$restarted -and (Test-Path -LiteralPath (Join-Path $reportDir 'restart-request.json'))) { Invoke-Compose restart mcp $ready = $false for ($attempt = 0; $attempt -lt 30; $attempt++) { & docker @composeArgs exec -T mcp python -c $healthProbe if ($LASTEXITCODE -eq 0) { $ready = $true; break } Start-Sleep -Seconds 1 } if (!$ready) { throw 'MCP did not recover after restart' } Set-Content -LiteralPath (Join-Path $reportDir 'restart-done.json') -Value '{"restarted":true}' -Encoding ascii $restarted = $true } $state = (& docker inspect --format '{{.State.Status}}' $testerName) if ($state -eq 'exited') { & docker logs $testerName $exitCode = [int](& docker inspect --format '{{.State.ExitCode}}' $testerName) if ($exitCode -ne 0) { throw "Capacity test failed (exit $exitCode)" } if (!$restarted) { throw 'Test finished without exercising restart' } return } Start-Sleep -Seconds 1 } throw 'Capacity test exceeded 20 minutes' } finally { if (!$KeepContainers) { & docker rm -f $testerName # Only this fixed disposable project and its named volumes are removed. & docker @composeArgs down -v } }