diff --git a/scripts/Run-AutonomousIntegrationLoop.ps1 b/scripts/Run-AutonomousIntegrationLoop.ps1 index 083a9ce9c..b1e9d7a39 100644 --- a/scripts/Run-AutonomousIntegrationLoop.ps1 +++ b/scripts/Run-AutonomousIntegrationLoop.ps1 @@ -471,17 +471,40 @@ if ($UseTestStandHarness) { if ($logDir -and -not (Test-Path -LiteralPath $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } } + $iterationExecutionTopology = [ordered]@{ + runtimeSurface = 'windows-native-teststand' + processModelClass = if ($TestStandSuiteClass -eq 'dual-plane-parity') { 'parallel-process-model' } else { 'sequential-process-model' } + windowsOnly = $true + requestedSimultaneous = ($TestStandSuiteClass -eq 'dual-plane-parity') + cellClass = $executionCellLeaseMetadata.cellClass + executionCellLeasePath = $executionCellLeasePath + executionCellId = $executionCellId + executionCellLeaseId = $executionCellLeaseId + harnessInstanceLeasePath = $harnessInstanceLeasePath + harnessInstanceLeaseId = $harnessInstanceLeaseMetadata.leaseId + harnessInstanceId = $harnessInstanceId + } + $exitCode = 0 - Write-JsonEvent 'harnessInvoke' @{ iteration=$currentIteration; output=$iterationRoot; status='start' } + Write-JsonEvent 'harnessInvoke' @{ iteration=$currentIteration; output=$iterationRoot; status='start'; executionTopology=$iterationExecutionTopology } try { & $resolvedHarness @harnessParams | Out-Null $exitCode = $LASTEXITCODE $sessionMetadata = Get-TestStandHarnessSessionMetadata -IterationRoot $iterationRoot if (-not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceId) -or -not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceLeaseId) -or -not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceLeasePath)) { $latestHarnessSessionMetadata.Value = $sessionMetadata + if (-not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceId)) { + $iterationExecutionTopology.harnessInstanceId = $sessionMetadata.harnessInstanceId + } + if (-not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceLeaseId)) { + $iterationExecutionTopology.harnessInstanceLeaseId = $sessionMetadata.harnessInstanceLeaseId + } + if (-not [string]::IsNullOrWhiteSpace($sessionMetadata.harnessInstanceLeasePath)) { + $iterationExecutionTopology.harnessInstanceLeasePath = $sessionMetadata.harnessInstanceLeasePath + } } } catch { - Write-JsonEvent 'harnessResult' @{ iteration=$currentIteration; status='exception'; message=$_.Exception.Message } + Write-JsonEvent 'harnessResult' @{ iteration=$currentIteration; status='exception'; message=$_.Exception.Message; executionTopology=$iterationExecutionTopology } throw } finally { if ($restoreHarnessLog) { @@ -490,7 +513,7 @@ if ($UseTestStandHarness) { $env:HARNESS_LOG = $originalHarnessLog } } - Write-JsonEvent 'harnessResult' @{ iteration=$currentIteration; exitCode=$exitCode } + Write-JsonEvent 'harnessResult' @{ iteration=$currentIteration; exitCode=$exitCode; executionTopology=$iterationExecutionTopology } return $exitCode } $skipValidation = $false @@ -697,6 +720,19 @@ if ($UseTestStandHarness -and $harnessPlan) { $planPayload.harnessRuntimeSurface = $harnessPlan.runtimeSurface $planPayload.harnessProcessModelClass = $harnessPlan.processModelClass $planPayload.harnessRequestedSimultaneous = $harnessPlan.requestedSimultaneous + $planPayload.executionTopology = [ordered]@{ + runtimeSurface = $harnessPlan.runtimeSurface + processModelClass = $harnessPlan.processModelClass + windowsOnly = $harnessPlan.windowsOnly + requestedSimultaneous = $harnessPlan.requestedSimultaneous + cellClass = $harnessPlan.cellClass + executionCellLeasePath = $harnessPlan.executionCellLeasePath + executionCellId = $harnessPlan.executionCellId + executionCellLeaseId = $harnessPlan.executionCellLeaseId + harnessInstanceLeasePath = $harnessPlan.harnessInstanceLeasePath + harnessInstanceLeaseId = $harnessPlan.harnessInstanceLeaseId + harnessInstanceId = $harnessPlan.harnessInstanceId + } } Write-JsonEvent 'plan' $planPayload @@ -715,6 +751,19 @@ if ($DryRun) { $dryRunPayload.harnessOutput = $harnessPlan.output $dryRunPayload.harnessRuntimeSurface = $harnessPlan.runtimeSurface $dryRunPayload.harnessProcessModelClass = $harnessPlan.processModelClass + $dryRunPayload.executionTopology = [ordered]@{ + runtimeSurface = $harnessPlan.runtimeSurface + processModelClass = $harnessPlan.processModelClass + windowsOnly = $harnessPlan.windowsOnly + requestedSimultaneous = $harnessPlan.requestedSimultaneous + cellClass = $harnessPlan.cellClass + executionCellLeasePath = $harnessPlan.executionCellLeasePath + executionCellId = $harnessPlan.executionCellId + executionCellLeaseId = $harnessPlan.executionCellLeaseId + harnessInstanceLeasePath = $harnessPlan.harnessInstanceLeasePath + harnessInstanceLeaseId = $harnessPlan.harnessInstanceLeaseId + harnessInstanceId = $harnessPlan.harnessInstanceId + } } Write-JsonEvent 'dryRun' $dryRunPayload Set-LoopExit 0 diff --git a/tests/Run-AutonomousIntegrationLoop.Tests.ps1 b/tests/Run-AutonomousIntegrationLoop.Tests.ps1 index 7e14f99de..aa0901b8d 100644 --- a/tests/Run-AutonomousIntegrationLoop.Tests.ps1 +++ b/tests/Run-AutonomousIntegrationLoop.Tests.ps1 @@ -108,6 +108,7 @@ Describe 'Run-AutonomousIntegrationLoop TestStand harness mode' -Tag 'Unit' { $harnessStub = Join-Path $outDir 'TestStand-CompareHarness.ps1' $logPath = Join-Path $outDir 'harness-log.ndjson' + $jsonLogPath = Join-Path $outDir 'loop.events.json' $outputRoot = Join-Path $outDir 'outputs' $stubContent = @" param( @@ -186,7 +187,7 @@ exit 0 try { $runner = Join-Path $outDir 'runner-harness.ps1' $runnerContent = @" -& '$scriptPath' -Base '$base' -Head '$head' -MaxIterations 2 -IntervalSeconds 0 -LogVerbosity Quiet -LvCompareArgs '-foo 1 -bar' -UseTestStandHarness -TestStandHarnessPath '$harnessStub' -TestStandOutputRoot '$outputRoot' -TestStandWarmup detect -TestStandSuiteClass dual-plane-parity -TestStandLabVIEW64Path 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandLabVIEW32Path 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandAgentId 'hooke' -TestStandAgentClass 'subagent' -TestStandExecutionCellLeasePath '$leasePath' -TestStandExecutionCellId 'exec-cell-hooke-loop-01' -TestStandExecutionCellLeaseId 'lease-hooke-loop-01' -TestStandHarnessInstanceLeasePath '$harnessLeasePath' -TestStandHarnessInstanceId 'ts-loop-hooke-01' -TestStandRenderReport -TestStandCloseLabVIEW -TestStandCloseLVCompare -TestStandTimeoutSeconds 45 -TestStandReplaceFlags -FinalStatusJsonPath '$outDir/final.json' +& '$scriptPath' -Base '$base' -Head '$head' -MaxIterations 2 -IntervalSeconds 0 -LogVerbosity Quiet -JsonLogPath '$jsonLogPath' -LvCompareArgs '-foo 1 -bar' -UseTestStandHarness -TestStandHarnessPath '$harnessStub' -TestStandOutputRoot '$outputRoot' -TestStandWarmup detect -TestStandSuiteClass dual-plane-parity -TestStandLabVIEW64Path 'C:\Program Files\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandLabVIEW32Path 'C:\Program Files (x86)\National Instruments\LabVIEW 2026\LabVIEW.exe' -TestStandAgentId 'hooke' -TestStandAgentClass 'subagent' -TestStandExecutionCellLeasePath '$leasePath' -TestStandExecutionCellId 'exec-cell-hooke-loop-01' -TestStandExecutionCellLeaseId 'lease-hooke-loop-01' -TestStandHarnessInstanceLeasePath '$harnessLeasePath' -TestStandHarnessInstanceId 'ts-loop-hooke-01' -TestStandRenderReport -TestStandCloseLabVIEW -TestStandCloseLVCompare -TestStandTimeoutSeconds 45 -TestStandReplaceFlags -FinalStatusJsonPath '$outDir/final.json' exit `$LASTEXITCODE "@ Set-Content -LiteralPath $runner -Encoding UTF8 -Value $runnerContent @@ -217,6 +218,20 @@ exit `$LASTEXITCODE $entries | ForEach-Object { $_.replaceFlags } | Sort-Object -Unique | Should -Be @($true) $entries | ForEach-Object { $_.flags } | ForEach-Object { $_ } | Sort-Object -Unique | Should -Be @('-bar','-foo','1') + $eventEntries = Get-Content -LiteralPath $jsonLogPath | ForEach-Object { $_ | ConvertFrom-Json } + $planEvent = $eventEntries | Where-Object { $_.type -eq 'plan' } | Select-Object -First 1 + $planEvent.executionTopology.runtimeSurface | Should -Be 'windows-native-teststand' + $planEvent.executionTopology.processModelClass | Should -Be 'parallel-process-model' + $planEvent.executionTopology.executionCellLeaseId | Should -Be 'lease-hooke-loop-01' + $planEvent.executionTopology.harnessInstanceLeaseId | Should -Be 'harness-lease-hooke-loop-01' + $planEvent.executionTopology.harnessInstanceId | Should -Be 'ts-loop-hooke-01' + + $lastHarnessResult = $eventEntries | Where-Object { $_.type -eq 'harnessResult' -and $_.PSObject.Properties.Name -contains 'exitCode' } | Select-Object -Last 1 + $lastHarnessResult.executionTopology.executionCellLeaseId | Should -Be 'lease-hooke-loop-01' + $lastHarnessResult.executionTopology.harnessInstanceLeaseId | Should -Be 'harness-lease-session-hooke-loop-01' + $lastHarnessResult.executionTopology.harnessInstanceLeasePath | Should -Be (Join-Path (Join-Path $outputRoot 'iteration-0002') 'session-harness-lease.json') + $lastHarnessResult.executionTopology.harnessInstanceId | Should -Be 'session-ts-loop-hooke-01' + $finalStatus = Get-Content -LiteralPath (Join-Path $outDir 'final.json') -Raw | ConvertFrom-Json $finalStatus.harness.path | Should -Be $harnessStub $finalStatus.harness.output | Should -Be $outputRoot