Skip to content

fix: eliminate port race in HTTP-transport e2e tests - #30

Draft
dzianisv wants to merge 2 commits into
mainfrom
fix/e2e-port-race
Draft

dzianisv wants to merge 2 commits into
mainfrom
fix/e2e-port-race

Conversation

@dzianisv

Copy link
Copy Markdown
Owner

Fixes the last red CI check (Compile and run tests).

Root cause

The e2e suite failed consistently in CI (every OS/node combo) with Server did not start within 15000ms, yet passed locally. Two bugs:

  1. Port TOCTOU race — getFreePort() bound port 0, read the port, closed the socket, returned the number. Under CI's parallel test execution a sibling grabbed the freed port before the spawned server bound it → child hit EADDRINUSE → walked its 1+2+4+8s retry backoff (~15s) → the 15s health-poll timed out.
  2. --port 0 fell through to stdio — if (args.port) is truthy, so port 0 never entered HTTP mode.

Fix

Spawn with --port 0 (OS assigns an ephemeral port atomically — never freed/re-grabbed), have the server report the actual bound port via httpServer.address(), and parse it from the server log in the test. Gate HTTP mode on args.port !== undefined.

This is a fork-only test (added in #4 for the Streamable-HTTP multi-agent feature; not present upstream). Validated locally: build + e2e suite + eslint + prettier all green. Relying on CI matrix to confirm the race fix.

🤖 Generated with Claude Code

engineer and others added 2 commits May 29, 2026 14:18
The e2e suite failed consistently in CI (all OS/node combos) with "Server
did not start within 15000ms", though it passed locally. Two bugs:

1. getFreePort() bound port 0, read the assigned port, closed the socket,
   then returned the number. Under CI's parallel test execution a sibling
   grabbed the freed port before the spawned server bound it, so the child
   hit EADDRINUSE and walked its 1+2+4+8s retry backoff (~15s) -> timeout.
2. `if (args.port)` is a truthy check, so `--port 0` fell through to stdio
   mode and the server exited immediately.

Fix: spawn the server with `--port 0` so the OS assigns an ephemeral port
atomically (never freed/re-grabbed), have the server report the actual
bound port via httpServer.address(), and parse it from the server log in
the test. Also gate HTTP mode on `args.port !== undefined`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dzianisv
dzianisv marked this pull request as draft May 29, 2026 21:50
@dzianisv

Copy link
Copy Markdown
Owner Author

Marking draft. The --port 0 race fix is correct and passes locally, but CI shows the e2e/daemon suite still fails for a deeper, pre-existing CI-environment reason — chrome-devtools-mcp daemon is not running and Windows named-pipe connect ENOENT \\.\pipe\...server.sock at spawnServer. Greening the full e2e/daemon job in CI is a separate infrastructure effort (Chrome setup, daemon lifecycle, Windows IPC, timeouts), not just the port race. Holding until that's scoped.

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