Skip to content

Replace free_port fixture with free_listener to prevent race condition in tests #258

@sourcery-ai

Description

@sourcery-ai

There is a potential race condition in the current implementation of the free_port fixture, which is used in both server_runtime.rs and server_runtime_more.rs. The fixture currently binds to a free port and immediately releases it, which can allow another process to claim the port before the test or server setup code does. This can lead to flaky tests or unexpected failures.

Suggested Solution:

  • Replace the free_port fixture with a free_listener fixture that returns a bound TcpListener. This keeps the port reserved until the test or server is ready to use it, preventing other processes from claiming the port in the meantime.
  • Update all tests and helpers that use free_port() to use free_listener() instead. If only the address is needed, extract it with listener.local_addr().unwrap().
  • Where possible, pass the TcpListener directly to the server setup code instead of just the address.

Example Implementation:

#[fixture]
/// Returns a bound TcpListener on a free port for use in tests.
/// This prevents race conditions by keeping the port reserved until the test is ready.
pub fn free_listener() -> std::net::TcpListener {
    let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0);
    std::net::TcpListener::bind(addr).expect("Failed to bind to localhost:0")
}

Action Items:

  1. Implement the free_listener fixture as shown above.
  2. Refactor all usages of free_port in the codebase to use free_listener.
  3. Update server setup code to accept a TcpListener where possible.
  4. Remove the old free_port fixture once all usages have been migrated.

Let us know if you need further guidance or code examples for the migration!

Issue: #258


I created this issue for @leynos from #244 (comment).

Tips and commands

Getting Help

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions