Skip to content

phoenixframework/phoenix

Back Harden and speed up phx.server integration test (#6818)

Commit details

Harden and speed up phx.server integration test (#6818)

Description

Previously, the integration test booted `phx.server` using `elixir -S mix` combined with an in-band stdin watcher. This had several shortcomings: 1. Portability: `elixir -S` loads scripts via `Code.require_file`, which fails with a syntax error in environments where `mix` in `$PATH` is a shell wrapper (such as standard `asdf` or `mise` shims). 2. Disk leak & Cleanup races: Running the server asynchronously inside `spawn_link` raced with `with_installer_tmp`'s directory cleanup, requiring `autoremove?: false` which permanently leaked generated apps on disk after every test run. 3. Test latency & Redundant work: A blind polling loop in `request_with_retries` imposed a 5-second sleep penalty on every test run, while `mix test` was redundantly executed inside a test strictly intended for server booting and HTTP readiness. This refactors the test to use deterministic, event-driven synchronization with a scoped `with_phx_server/2` helper: - Uses `Port.open` to launch Mix directly as an OS executable. - Synchronizes the test and server processes via an explicit readiness marker emitted only after the endpoint has bound the listening port, eliminating polling latency. - Handles premature child exits immediately to fail fast instead of timing out. - Signals child process shutdown via standard input and awaits child OS process termination before returning. This guarantees lock release before `with_installer_tmp` deletes the temporary directory. - Restores automatic cleanup (`autoremove?: true`) in `with_installer_tmp`. - Lowers execution time of this test file by ~40% (from ~35s to ~20s locally on Apple M4; previously ~52s in CI) by eliminating the blind polling sleep and focusing the test strictly on server boot. Notes & Platform Considerations: - Helper scope: `with_phx_server/2` and HTTP helpers are intentionally kept private to this test file for now since it is currently the only test verifying server boot. - Separation of concerns: Scaffolded test execution is validated by dedicated code generator suites, keeping this test focused exclusively on server startup and HTTP readiness. - Inets application: Removed redundant explicit `:inets.start()` call from the test since `:inets` is already started as part of `extra_applications` in `integration_test/mix.exs`. - Port binding & async execution: The test verifies the out-of-the-box development workflow by booting `phx.server` on the default port 4000 under `async: true`. Binding a fixed OS port poses a collision risk (`:eaddrinuse`) if a developer is running a local dev server or if additional server tests are added in the future. We evaluated this tradeoff and decided to keep the fixed port for now since it matches the status quo and this is currently the only test booting a server; dynamic port handling can be revisited if more server tests are introduced. - Windows compatibility: On Windows, `System.find_executable("mix")` resolves to `mix.bat`. As specified in Erlang/OTP's `open_port/2` documentation, ERTS natively dispatches `.bat` scripts through `cmd.exe` on Windows. Note that the integration test suite is not explicitly exercised on Windows in CI (which runs on Linux).

Metadata

Author
Rodolfo Carvalho rhcarvalho@gmail.com
Committed
Commit

Contributors

  • Rodolfo Carvalho rhcarvalho@gmail.com Author