Sitelet https://github.com/PowerShell/PowerShell/pull/27883
Skip to content

Fix flaky Debug-Runspace attach event test - #27883

Open
Travis Plunk (TravisEz13) wants to merge 1 commit into
PowerShell:masterfrom
TravisEz13:fix-debug-runspace-flaky-attach-test
Open

Fix flaky Debug-Runspace attach event test#27883
Travis Plunk (TravisEz13) wants to merge 1 commit into
PowerShell:masterfrom
TravisEz13:fix-debug-runspace-flaky-attach-test

Conversation

@TravisEz13

Copy link
Copy Markdown
Member

PR Summary

Fixes the flaky Debug-Runspace test Should write attach event and mark runspace as having a remote debugger attached, which intermittently fails in CI at:

$waitTask.AsyncWaitHandle.WaitOne(5000) | Should -BeTrue
Expected $true, but got $false.

Root cause (test-side race, not a product bug)

The test did:

$debugTarget = [PowerShell]::Create()          # runspace created but NOT opened
$null = $debugTarget.AddCommand('Wait-Event')...
$waitTask = $debugTarget.BeginInvoke()         # opens runspace + starts pipeline asynchronously
$debugger.AddCommand('Debug-Runspace').AddParameter('Id', $debugTarget.Runspace.Id)
$debugTask = $debugger.BeginInvoke()           # starts immediately, no synchronization

BeginInvoke only queues work. Nothing guaranteed the target runspace had finished opening before Debug-Runspace executed. When Debug-Runspace won the race, either:

  1. DebugRunspaceCommand.EndProcessing operated on a runspace that was not Opened, producing a terminating InvalidOperation error before ever reaching the event generation, or
  2. _runspace.Events?.GenerateEvent(...) (DebugRunspaceCommand.cs:269) was skipped by the null-conditional because the runspace's execution context / event manager was not yet available.

Either way OnDebugAttach was never delivered and the 5-second wait timed out.

Note the fix must gate on runspace readiness, not merely on subscriber registration: an event generated before Wait-Event reaches ProcessRecord is not lost, because WaitEventCommand.ScanEventQueue drains Events.ReceivedEvents on entry.

Fix

Test-only changes — no production code modified:

  • Explicitly create and Open() the target runspace and assign it to the PowerShell instance, eliminating the "runspace not yet open" window and guaranteeing a live event manager.
  • Before invoking Debug-Runspace, gate on real readiness with the existing Wait-UntilTrue helper: the pipeline's InvocationStateInfo.State is Running and the runspace's RunspaceAvailability is Busy. This is a bounded readiness gate, not a fixed sleep or an inflated timeout.
  • Wait deterministically for IsRemoteDebuggerAttached to return to $false, since the cmdlet resets it while unwinding asynchronously with respect to Stop().
  • Wrap the body in try/finally so the debugger PowerShell, target PowerShell, and the runspace are stopped and disposed even when an assertion fails.

All four original assertions are preserved: OnDebugAttach received, IsRemoteDebuggerAttached becomes $true, stopping throws PipelineStoppedException, and IsRemoteDebuggerAttached returns to $false.

PR Context

Removes a source of intermittent Windows CI failures.

PR Checklist

  • PR has a meaningful title
  • Summarized changes
  • Make sure all .h, .cpp, .cs, .ps1 and .psm1 files have the correct copyright header
  • This PR is ready to merge and is not work in progress
    • User-facing changes: N/A (test-only)
    • Testing - New and existing tests pass

Test Results

Built locally (Start-PSBuild, Windows, Debug) and run against the fresh pwsh:

Describing Debug-Runspace
  [+] Debugging a runspace should fail if the name is ambiguous
  [+] Debugging a runspace should fail if the name is not found
  [+] Debugging a runspace should fail if the runspace is not open
  [+] Debugging a runspace should fail if the runspace has no debugger
  [+] Should write attach event and mark runspace as having a remote debugger attached
Tests Passed: 5, Failed: 0

Repeated 10 consecutive standalone runs: P=5 F=0 every time.

Via the repo harness, including the closely related debugger suite:

Start-PSPester -Path test/.../Debug-Runspace.Tests.ps1, test/.../RunspaceBreakpointManagement.Tests.ps1
Tests Passed: 25, Failed: 0, Skipped: 0, Pending: 0, Inconclusive: 0

The test started a 'Wait-Event' pipeline with BeginInvoke on a PowerShell instance whose runspace was not yet opened, then immediately started Debug-Runspace against that runspace id. Nothing synchronized the two, so Debug-Runspace could run before the target runspace was open/executing, in which case the cmdlet errored out or skipped the null-conditional Events.GenerateEvent call and OnDebugAttach never fired.

Open the target runspace explicitly, gate on the Wait-Event pipeline actually running before attaching, wait deterministically for detach, and dispose all instances in a finally block. Assertions are unchanged and no production code was modified.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2a30274b-8dba-4f6b-92b3-e715b633f8b3
Copilot AI lite review requested due to automatic review settings August 25, 2026 17:45
@TravisEz13
Travis Plunk (TravisEz13) requested a review from a team as a code owner August 25, 2026 17:45
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the Debug-Runspace Pester test that intermittently timed out waiting for the OnDebugAttach engine event by eliminating a runspace startup race and adding deterministic readiness/cleanup logic.

Changes:

  • Creates and opens the target runspace explicitly before starting Wait-Event, ensuring the runspace is Opened and has an initialized event manager.
  • Gates the debugger attach on actual pipeline/runspace readiness using Wait-UntilTrue (pipeline state Running + runspace availability Busy) rather than relying on timing.
  • Adds deterministic detach waiting and try/finally cleanup to stop/dispose PowerShell instances and the created runspace even on assertion failures.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants