microsoft / microsoft/aspire

Make acquisition script host fixture robust against listener teardown races

Open
#16,471 0 comments 1 reaction 2 assignees Claimed by @radical View on GitHub
area-engineering-systems
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.