Make acquisition script host fixture robust against listener teardown races
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Summary
`Aspire.Acquisition.Tests.Scripts.PipedInstallTests` currently hosts acquisition scripts through `ScriptHostFixture`, which uses `HttpListener` on a probed localhost port. This is fragile under CI parallelism and produced cleanup failures where otherwise-passing tests failed during fixture disposal:
```text
Xunit.MicrosoftTestingPlatform.XunitException: Class fixture type 'Aspire.Acquisition.Tests.Scripts.ScriptHostFixture' threw in DisposeAsync
---- System.Net.HttpListenerException : Address already in use
at System.Net.HttpEndPointManager.GetEPListener(String host, Int32 port, HttpListener listener, Boolean secure)
at System.Net.HttpEndPointManager.RemovePrefixInternal(String prefix, HttpListener listener)
at System.Net.HttpEndPointManager.RemoveListener(HttpListener listener)
at System.Net.HttpListener.Close(Boolean force)
at System.Net.HttpListener.Dispose()
at System.Net.HttpListener.Close()
at Aspire.Acquisition.Tests.Scripts.ScriptHostFixture.DisposeAsync() in /_/tests/Aspire.Acquisition.Tests/Scripts/Common/ScriptHostFixture.cs:117
```
Example run/job: https://github.com/microsoft/aspire/actions/runs/24950314407/job/73059291257?pr=16454
PR #16454 added a short-term mitigation so teardown exceptions after cancellation do not fail the class, but the fixture should be made structurally robust.
## Proposed follow-up
Replace the `HttpListener` implementation in `ScriptHostFixture` with a tiny Kestrel-based test server bound to loopback port `0`.
This would:
- avoid the current free-port probe then bind TOCTOU window
- avoid `HttpListener` process-global prefix teardown behavior
- let the OS allocate the port atomically and read it from the bound server address
- keep startup/bind failures loud while making shutdown deterministic
## Suggested validation
- Add regression coverage that repeatedly initializes and disposes `ScriptHostFixture`.
- Run `Aspire.Acquisition.Tests` with normal parallelization enabled.
- Verify `PipedInstallTests` still exercises the documented `curl | bash` and `irm | iex` flows against a real local HTTP endpoint.
Contributor guide
Assessment
This issue has not been assessed yet.