Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions tests/Local-Runbook.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Describe 'Local-Runbook topology summary' -Tag 'Unit' {
It 'auto-stages a runbook report for loop runs and prints loop execution topology' {
$repoRoot = Join-Path $TestDrive 'repo'
$toolsDir = Join-Path $repoRoot 'tools'
$scriptsDir = Join-Path $repoRoot 'scripts'
New-Item -ItemType Directory -Path $toolsDir -Force | Out-Null
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null

Copy-Item -LiteralPath (Join-Path $PSScriptRoot '..' 'tools' 'Local-Runbook.ps1') -Destination (Join-Path $toolsDir 'Local-Runbook.ps1') -Force

$stub = @"
param(
[switch]`$All,
[string[]]`$Phases,
[string]`$JsonReport,
[switch]`$FailOnDiff,
[switch]`$PassThru
)
if ([string]::IsNullOrWhiteSpace(`$JsonReport)) {
throw 'Expected JsonReport path'
}
`$payload = [ordered]@{
schema = 'integration-runbook-v1'
generated = '2026-03-24T13:00:00Z'
overallStatus = 'Passed'
phases = @(
[ordered]@{
name = 'Loop'
status = 'Passed'
details = [ordered]@{
executionTopology = [ordered]@{
runtimeSurface = 'windows-native-teststand'
processModelClass = 'parallel-process-model'
executionCellLeaseId = 'lease-hooke-loop-01'
harnessInstanceLeaseId = 'harness-lease-hooke-loop-01'
harnessInstanceId = 'ts-hooke-loop-01'
}
}
}
)
}
(`$payload | ConvertTo-Json -Depth 8) | Set-Content -LiteralPath `$JsonReport -Encoding UTF8
exit 0
"@
Set-Content -LiteralPath (Join-Path $scriptsDir 'Invoke-IntegrationRunbook.ps1') -Value $stub -Encoding UTF8

Push-Location $repoRoot
try {
$output = & pwsh -NoLogo -NoProfile -File (Join-Path $toolsDir 'Local-Runbook.ps1') -Profile loop 2>&1 | Out-String
$LASTEXITCODE | Should -Be 0
} finally {
Pop-Location
}

$output | Should -Match 'Loop Execution Topology:'
$output | Should -Match 'runtimeSurface: windows-native-teststand'
$output | Should -Match 'processModelClass: parallel-process-model'
$output | Should -Match 'executionCellLeaseId: lease-hooke-loop-01'
$output | Should -Match 'harnessInstanceLeaseId: harness-lease-hooke-loop-01'
$output | Should -Match 'harnessInstanceId: ts-hooke-loop-01'
}
}
64 changes: 61 additions & 3 deletions tools/Local-Runbook.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,61 @@ $ErrorActionPreference = 'Stop'
$scriptRoot = Split-Path -Parent $PSCommandPath
$repoRoot = Resolve-Path (Join-Path $scriptRoot '..') | Select-Object -ExpandProperty Path

function Get-EffectiveJsonReportPath {
param(
[AllowNull()][string]$RequestedPath,
[string[]]$SelectedPhases,
[switch]$RunAll,
[string]$RepoRoot
)

if (-not [string]::IsNullOrWhiteSpace($RequestedPath)) {
return $RequestedPath
}

if ($RunAll -or ($SelectedPhases -contains 'Loop')) {
$outDir = Join-Path $RepoRoot 'tests' 'results' '_agent' 'local-runbook'
if (-not (Test-Path -LiteralPath $outDir)) {
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
}
return (Join-Path $outDir 'local-runbook-report.json')
}

return $null
}

function Write-LoopExecutionTopologySummary {
param([AllowNull()][string]$JsonReportPath)

if ([string]::IsNullOrWhiteSpace($JsonReportPath)) {
return
}
if (-not (Test-Path -LiteralPath $JsonReportPath -PathType Leaf)) {
return
}

try {
$report = Get-Content -LiteralPath $JsonReportPath -Raw | ConvertFrom-Json -ErrorAction Stop
$loopPhase = @($report.phases) | Where-Object { $_.name -eq 'Loop' } | Select-Object -First 1
if (-not $loopPhase) {
return
}
$executionTopology = if ($loopPhase.details.PSObject.Properties.Name -contains 'executionTopology') { $loopPhase.details.executionTopology } else { $null }
if (-not $executionTopology) {
return
}

Write-Output 'Loop Execution Topology:'
if ($executionTopology.runtimeSurface) { Write-Output (" runtimeSurface: {0}" -f $executionTopology.runtimeSurface) }
if ($executionTopology.processModelClass) { Write-Output (" processModelClass: {0}" -f $executionTopology.processModelClass) }
if ($executionTopology.executionCellLeaseId) { Write-Output (" executionCellLeaseId: {0}" -f $executionTopology.executionCellLeaseId) }
if ($executionTopology.harnessInstanceLeaseId) { Write-Output (" harnessInstanceLeaseId: {0}" -f $executionTopology.harnessInstanceLeaseId) }
if ($executionTopology.harnessInstanceId) { Write-Output (" harnessInstanceId: {0}" -f $executionTopology.harnessInstanceId) }
} catch {
Write-Warning ("Failed to read loop execution topology from JSON report: {0}" -f $_.Exception.Message)
}
}

Push-Location $repoRoot
try {
Write-Host "=== Local Runbook ===" -ForegroundColor Cyan
Expand Down Expand Up @@ -50,14 +105,15 @@ try {
$env:RUNBOOK_LOOP_ITERATIONS = '1'
$env:RUNBOOK_LOOP_QUICK = '1'
if ($FailOnDiff) { $env:RUNBOOK_LOOP_FAIL_ON_DIFF = '1' } else { Remove-Item Env:RUNBOOK_LOOP_FAIL_ON_DIFF -ErrorAction SilentlyContinue }
$effectiveJsonReport = Get-EffectiveJsonReportPath -RequestedPath $JsonReport -SelectedPhases $selectedPhases -RunAll:$All -RepoRoot $repoRoot

$runbookArgs = @()
if ($All) { $runbookArgs += '-All' }
if ($selectedPhases.Count -gt 0 -and -not $All) {
$runbookArgs += @('-Phases', ($selectedPhases -join ','))
}
if ($FailOnDiff) { $runbookArgs += '-FailOnDiff' }
if ($JsonReport) { $runbookArgs += @('-JsonReport', $JsonReport) }
if ($effectiveJsonReport) { $runbookArgs += @('-JsonReport', $effectiveJsonReport) }
if ($PassThru) { $runbookArgs += '-PassThru' }

Write-Host "Invoking Invoke-IntegrationRunbook.ps1 with arguments:" -ForegroundColor Gray
Expand All @@ -66,8 +122,10 @@ try {
$runbookArgs | ForEach-Object { Write-Host (" {0}" -f $_) -ForegroundColor DarkGray }
}

& "$repoRoot/scripts/Invoke-IntegrationRunbook.ps1" @runbookArgs
exit $LASTEXITCODE
& pwsh -NoLogo -NoProfile -File "$repoRoot/scripts/Invoke-IntegrationRunbook.ps1" @runbookArgs
$runbookExitCode = $LASTEXITCODE
Write-LoopExecutionTopologySummary -JsonReportPath $effectiveJsonReport
exit $runbookExitCode
}
finally {
Pop-Location
Expand Down
Loading