Skip to content

[RT-SW-421] test: the loopback probe's closed endpoint is a port no parallel test can be handed - #422

Merged
Blind-Striker merged 1 commit into
masterfrom
fix/421-loopback-closed-endpoint
Oct 17, 2026
Merged

Blind-Striker merged 1 commit into
masterfrom
fix/421-loopback-closed-endpoint

Conversation

@Blind-Striker

@Blind-Striker Blind-Striker commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

What

The loopback probe tests' "closed" endpoint can no longer be a port that a parallel test is handed. Test-only.

Closes #421.

Cause

LoopbackTransportTests.ClosedEndpointAsync() started a LoopbackHttpServer, disposed it, and returned the port it had just released. That port belongs to the platform's ephemeral range. A parallel test binding port 0 could be handed it before the probe connected, and then the "refused" verdict became a connect. This happened on net472 on master 380fd540, on an unchanged tree.

The change

ClosedEndpoint() finds a free loopback port below every platform's ephemeral range with a bind, starting at 20000, and releases it. No port-0 bind is ever handed such a port, so nothing in the suite can take it. Every call takes its own candidates from a process-wide Interlocked counter. The class's four callers run in parallel, and on macOS a port that another caller is momentarily binding would time out instead of refusing; with the counter, two callers never try the same port. All four callers are unchanged except for that one arrange line. No retry, no widened bound, no new type.

Why not a socket held bound but not listening

That was the first idea. Measured on three OSes, it fails twice:

  • macOS: a connect to such a port times out instead of being refused.
  • Linux: .NET's TcpListener can rebind the held port, so the hold reserves nothing.

Proof (probes run on all three OSes, not committed; scratchpad scripts)

Windows macOS (Intel) Linux (WSL2)
Old: a released port rebound by another listener, then connected connected (the flake) connected connected
New: a free port at 20000, released, then connected ConnectionRefused ConnectionRefused ConnectionRefused
Lowest port among 2,000 port-0 listeners 61528 59447 32773
  • LoopbackTransportTests passes on net10.0 (10/10) and net472 (17/17).
  • Both format passes; verify-clones 0 new; the repository guards 93/93.
  • CI's three legs are the platform proof for the committed tests.

@Blind-Striker
Blind-Striker force-pushed the fix/421-loopback-closed-endpoint branch 2 times, most recently from 9a811ad to 4b4b69c Compare October 17, 2026 05:58
… can be handed (#421)

ClosedEndpointAsync disposed a server and returned its released ephemeral port,
which a parallel test binding port 0 could be handed before the probe connected,
so a refusal turned into a connect. The closed endpoint is now a free port below
every platform's ephemeral range (Windows/macOS 49152+, Linux 32768+).
@Blind-Striker
Blind-Striker force-pushed the fix/421-loopback-closed-endpoint branch from 4b4b69c to 45f1620 Compare October 17, 2026 06:01
@Blind-Striker
Blind-Striker added this pull request to the merge queue Oct 17, 2026
Merged via the queue into master with commit b7df197 Oct 17, 2026
12 checks passed
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.

LoopbackTransportTests: the 'closed' endpoint is a released port a parallel test can rebind

1 participant