test(e2e): prove the gateway happy path over the CLI and HTTP (ADR 0005) - #132
Open
V3RON wants to merge 1 commit into
Open
test(e2e): prove the gateway happy path over the CLI and HTTP (ADR 0005)#132V3RON wants to merge 1 commit into
V3RON wants to merge 1 commit into
Conversation
Four smoke tests for the seam nothing covered: a real gateway process, real worker processes on a real uplink, and a client reaching the fleet the way a user does. `src/daemon/gateway-fleet.e2e.test.ts` already proved lease routing and a real `device.exec` across two workers, but through the daemon's own `dispatch()` in-process. Everything between that dispatcher and a user was unproven for gateway mode: the CLI's gateway/worker branch, the HTTP lease and exec routes against a gateway, SSE streaming of proxied output, exit-code propagation. The one out-of-process lease that existed went deliberately to a worker's own socket, because fleet routing belonged to a later PR than the one that wrote it -- that PR has landed and nothing came back to close the gap. 1. CLI: `simlock lease` against a gateway, the grant's `worker` block and worker-named id, the worker's own view showing §27a's namespaced requester, then `simlock adb` taking the gateway branch (`device.exec` rather than a local spawn), streaming both streams and exiting with the tool's own code. 2. HTTP: lease request to granted, exec streaming SSE with a real exit code, a silent long-running command answered while it still runs, and a pre-process refusal keeping its own 422 instead of a committed 200. 3. Fleet-wide FIFO: `REQUESTER_ALREADY_LEASED`, `--no-wait` `NO_CAPACITY`, a waiter reporting `queued` at position 1 and served on release. 4. Renew/release: an over-cap `--ttl` refused gateway-side (§15), the gateway-issued id round-tripping through `status` and `lease renew`. `--fake-exec-silent` and `--fake-exec-sleep` are new on the fake driver's passthrough program, and exist for one assertion. §19a's `started` push buys a transport *timing*, not status: `http/app.ts` races the command settling against `started`, so a command that merely succeeds reaches the same committed 200 either way -- just not until it exits. Only a command that is both silent and slow separates them. Every existing fixture writes its argv and would let a first-chunk fallback pass identically. That assertion took three attempts, and the first two are why the third is worth having. Billing the 422 refusal as "the only end-to-end test of `started`" was simply false -- it passes with the gateway's relay ripped out, as does a short silent command. Neutering `FleetLeaseCoordinator#exec`'s `onStarted` now fails exactly one assertion, `expected 4049 to be less than 2000`: the response head arriving only after the command exited. The CLI test passes `input: ""`, which models `simlock adb ... < /dev/null`. That is load-bearing, not tidiness: against a worker the CLI spawns the tool with inherited stdio and never reads stdin, but against a gateway it must read stdin to EOF before it can send the one `stdin` string `device.exec` carries. The harness spawns with a pipe it never closes, so without it the CLI waits for an EOF that never comes -- as a real caller handing simlock an open pipe would. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MA98m7ua7qvDFZjxFaww6Z
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #131. Four smoke tests for the seam nothing covered: a real gateway process, real worker processes on a real uplink, and a client reaching the fleet the way a user does.
Why
src/daemon/gateway-fleet.e2e.test.tsalready proves lease routing and a realdevice.execacross two worker processes — but through the daemon's owndispatch(), in-process. Everything between that dispatcher and a user was unproven for gateway mode: the CLI's gateway/worker branch, the HTTP lease and exec routes against a gateway, SSE streaming of proxied output, and exit-code propagation.The one out-of-process lease that existed (
e2e/gateway-fleet.test.ts) deliberately went straight to a worker's own socket, with a comment saying fleet routing belonged to a later PR than the one that wrote it. That PR has since landed and nothing came back to close the gap.The tests
simlock leasegives a grant carrying itsworkerblock and a worker-named id; the worker's ownstatusshows §27a's namespaced requester (gw:<instance>:<agent>);simlock adbtakes the gateway branch (device.execrather than a local spawn), streams both streams, and exits with the tool's own code;release.422 PASSTHROUGH_REFUSEDinstead of a committed200.REQUESTER_ALREADY_LEASED(13),--no-wait→NO_CAPACITY(11), a waiter reportingqueuedat position 1 and served on release.--ttlrefused gateway-side (§15), and the gateway-issued id round-tripping throughstatusandlease renew.These are smoke tests: they prove the layers are wired to each other, not that the routing policy, queue ordering or refusal lists are correct.
src/gateway's own suites own that.Two new fake-driver flags, for one assertion
--fake-exec-silentand--fake-exec-sleep=<ms>exist together to pin ADR §19a'sstartedpush end to end.What
startedbuys a transport is timing, not status:http/app.tsraces the command settling againststarted, so a command that merely succeeds reaches the same committed200either way — just not until it exits. Only a command that is both silent and slow separates them. Every existing fixture writes its argv and would let a first-chunk fallback pass identically.That assertion took three attempts, and the first two are why the third is worth having. Billing the
422refusal as "the only end-to-end test ofstarted" was false — it passes with the gateway's relay ripped out, as does a short silent command. NeuteringFleetLeaseCoordinator#exec'sonStartednow fails exactly one assertion:expected 4049 to be less than 2000, the response head arriving only after the command exited.One harness subtlety worth knowing
The CLI test passes
input: "", modellingsimlock adb ... < /dev/null. That is load-bearing rather than tidiness: against a worker the CLI spawns the tool with inherited stdio and never reads stdin, but against a gateway it must read stdin to EOF before it can send the onestdinstringdevice.execcarries. The e2e harness spawns with a pipe it never closes, so without this the CLI waits for an EOF that never comes — exactly what a real caller handing simlock an open pipe would see.Verification
device-execandlease-environment-passthroughre-run and unaffected by the fake-driver change🤖 Generated with Claude Code
https://claude.ai/code/session_01MA98m7ua7qvDFZjxFaww6Z
Generated by Claude Code