Skip to content

Commit 71416ff

Browse files
Restore E2E test hardening reverted with the Windows PowerShell skips
PR #2328 reset the three E2E test files to their pre-#2318 state (`b57653c40`) to undo the Windows PowerShell skips we no longer want now that the host-start hang is actually fixed. But #2318 was a squash that bundled genuine harness hardening *alongside* those skips, so reverting wholesale quietly dropped the good parts too. Restore just those, keeping the skips reverted: - `ReadScriptLogLineAsync` now yields with `await Task.Delay(100)` at EOF instead of busy-spinning. At EOF `ReadLineAsync` completes synchronously with `null`, so the old `while`/`await` loop never released its thread-pool thread and could starve the scheduler on constrained CI runners. - The child-process `Debug-Runspace` readiness poll in `CanAttachScriptWithPathMappings` sleeps 100ms per iteration so it can't peg a core during the attach handshake. - `LSPTestsFixture.DisposeAsync` guards against a null `PsesLanguageClient` so a startup failure isn't masked by a `NullReferenceException` during teardown. These are defense-in-depth independent of the skips, and they matter more now that we un-skip: a Windows PowerShell server that fails to start shouldn't busy-spin or NRE on teardown. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1979e51 commit 71416ff

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

‎test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,22 @@ private async Task<string> ReadScriptLogLineAsync()
238238
}
239239
}
240240

241-
// return valid lines only
242-
string nextLine = string.Empty;
243-
while (nextLine is null || nextLine.Length == 0)
241+
// Tail the log until a non-empty line is available. The awaited
242+
// delay between reads matters: at EOF ReadLineAsync completes
243+
// synchronously with null, so without it this is a tight loop that
244+
// never releases its thread-pool thread and needlessly pressures
245+
// the pool on constrained CI runners. Yielding keeps the tail loop
246+
// cheap while we wait for the script to write.
247+
while (true)
244248
{
245-
nextLine = await scriptLogReader.ReadLineAsync(); //Might return null if at EOF because we created it above but the script hasn't written to it yet
249+
string nextLine = await scriptLogReader.ReadLineAsync();
250+
if (!string.IsNullOrEmpty(nextLine))
251+
{
252+
return nextLine;
253+
}
254+
255+
await Task.Delay(100);
246256
}
247-
return nextLine;
248257
}
249258

250259
[Fact]
@@ -762,6 +771,10 @@ WinPS will always need this.
762771
if (((Get-Date) - $start).TotalSeconds -gt 10) {
763772
throw 'Timeout waiting for Debug-Runspace to be subscribed.'
764773
}
774+
775+
# Yield a slice so this poll doesn't peg a core while the
776+
# runner is also servicing the attach handshake.
777+
Start-Sleep -Milliseconds 100
765778
}
766779
767780
$ps.Invoke()

‎test/PowerShellEditorServices.Test.E2E/LSPTestsFixtures.cs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,19 @@ public async Task InitializeAsync()
100100

101101
public async Task DisposeAsync()
102102
{
103+
// If InitializeAsync failed before the client connected (e.g. the
104+
// server never finished starting), PsesLanguageClient was never
105+
// assigned, so there is nothing to shut down. Guarding here keeps a
106+
// startup failure from being masked by a NullReferenceException
107+
// during teardown.
108+
if (PsesLanguageClient is null)
109+
{
110+
return;
111+
}
112+
103113
await PsesLanguageClient.Shutdown();
104114
await _psesHost.Stop();
105-
PsesLanguageClient?.Dispose();
115+
PsesLanguageClient.Dispose();
106116
}
107117
}
108118
}

0 commit comments

Comments
 (0)