Skip to content

Fix flaky moto_server fixture by using an OS-assigned ephemeral port - #3759

Open
puchengy wants to merge 1 commit into
apache:mainfrom
puchengy:fix-flaky-moto-server-port
Open

Fix flaky moto_server fixture by using an OS-assigned ephemeral port#3759
puchengy wants to merge 1 commit into
apache:mainfrom
puchengy:fix-flaky-moto-server-port

Conversation

@puchengy

@puchengy puchengy commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Rationale for this change

The moto_server session fixture in tests/conftest.py hardcodes port 5001 and pre-binds a socket to it purely to detect conflicts (added in #292). This is still flaky: when the test session runs on a shared/parallel CI runner, or when a previous run left the port in TIME_WAIT, the pre-bind raises and fails the entire test session at fixture setup:

ERROR at setup of test_...
OSError: [Errno 98] Address already in use
tests/conftest.py: OSError

Bumping the port (as #292 did, 5000 → 5001) and failing fast doesn't remove the collision — it only surfaces it sooner.

This change binds to port 0 so the OS assigns a free ephemeral port, then reads the actual bound port back via moto's get_host_and_port(). That eliminates the collision entirely and removes the now-unnecessary pre-bind check (and the socket import). The fixture's return annotation is also corrected to Generator[...] since it yields.

Are these changes tested?

Yes — existing moto-backed tests continue to pass against the new fixture (e.g. tests/catalog/test_glue.py S3 tests, which consume moto_endpoint_url). Verified locally that ThreadedMotoServer(port=0) starts, get_host_and_port() returns a real ephemeral port, serves requests, and stops cleanly. ruff check tests/conftest.py passes.

Are there any user-facing changes?

No. Test-infrastructure only.

The `moto_server` session fixture hardcoded port 5001 and pre-bound a
socket to it purely to detect conflicts (added in apache#292). This is still
flaky: when tests run in parallel (e.g. multiple CI jobs on a shared
runner) or when a previous run leaves the port in TIME_WAIT, the pre-bind
raises `OSError: [Errno 98] Address already in use`, failing the whole
test session at fixture setup.

Bind to port 0 instead so the OS assigns a free ephemeral port, and read
the actual bound port back via moto's `get_host_and_port()`. This removes
the collision and the now-unnecessary pre-bind check (and the `socket`
import). The fixture return annotation is corrected to `Generator[...]`
since it yields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant