Repository navigation
Add spawned server contexts, split raw peers and a two-way streaming case to base-http-fixtures. - #49
Merged
Merged
Conversation
…case to `base-http-fixtures`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rect what the fixtures documentation claims about buffering and scheduler drains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and make the two-way stream and its stall tests independent of socket buffer sizes. `ServerContext::run_spawned` now owns its scheduler and the application, and the test receives the same `Context<'_, NativeScheduler, H>` as `run`. Spawning, joining and the shared scheduler are private, so `ServerContext::spawn`, `run_spawned_on`, `SpawnedServer` and `shared_native` are gone, along with the drop paths. A unit test runs a blocking handler on a one-worker scheduler and shows that the join still fails within its timeout. `duplex_stream` keeps its upload within `DUPLEX_WINDOW` of the echo received, so a server which buffers the request instead of streaming it stalls the case, as a new sabotage test shows. The sequential stall tests declare 1 GiB and assert that the upload stopped short. A new test shows that a split raw peer keeps its buffered input. The documentation and design now say that a poll which never returns cannot be preempted, so it hangs the scheduler's shutdown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g against a reframed echo, and mark the own-thread join deadline as temporary.
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.
Adds a spawned mode to
base-http-fixtures. The server runs on the scheduler's workers while the test drives the client from its own thread, so cross-thread wake-up bugs and races can show up. It also addsRawPeer::splitfor raw peers that upload and download at the same time, and a two-way streaming case in the shared protocol suite. This follows #48.Spawned server context
ServerContext::run_spawned(test)is the only new public entry point. It creates its own two-worker Native scheduler, takes ownership of the application, binds the listener, then spawnsbase_http_server::serveorserve_tls, unchanged, as one task throughbase_scheduler::Spawn.Context<'_, NativeScheduler, H>asrun, andhandler()returns&H. TheArcs that the server's'statictask needs, for both the scheduler and the application, stay inside the fixture. No spawned-server handle is exposed, so there is no shutdown for a test to forget and no drop path.Handler + Send + Sync + 'static, which is what a server that spawned its own connection tasks would need.base-http-serveris not touched, and nothing chooses how connections are spread across tasks or workers.run:crates/fixtures/src/context/tests.rsblocks the only worker of a one-worker scheduler and shows that the join still fails within 50 ms.Raw peers
RawPeer::split()returns aRawReaderand aRawWriter.BufReader. The writer is aTcpStream::try_cloneof the socket, so it shares the peer's timeouts.a_split_raw_peer_keeps_its_buffered_inputbuffers a second line before splitting and reads it through the reader.a_split_raw_peer_uploads_and_downloads_at_oncestreams 16 MiB up and down at the same time from two threads.a_sequential_raw_upload_stalls_under_backpressuredeclares a 1 GiB upload, writes it on one thread without reading, and requires the write timeout to hit before the upload ends. 1 GiB is far beyond any socket buffering, so the result doesn't depend on the host's buffer sizes.Suites
duplex_streamstreamsDUPLEX_BODY(16 MiB) to a new/duplexecho route and reads the echo at the same time. It runs inprotocol_tests!.DUPLEX_WINDOW(four 16 KiB chunks) ahead of the echo received. The case can finish only if the client delivers the response while still sending the request, and the server echoes the request while still receiving it.the_duplex_stream_stalls_against_a_buffering_servershows that a server which collects the request before replying stalls the case. The same sabotage applied toApp's/duplexfails all six runner variants.a_sequential_duplex_stream_stallsuploads a 1 GiB request through the client before reading the echo. It samples the bytes written at 250 ms and 500 ms and requires that they are equal, so a client that keeps uploading fails it.duplex_chunked_streamruns the same windowed exchange through/duplex-chunked, where the server echoes the request asReply::Stream, a body with no length that may have trailers. Over HTTP/1.1 the response is therefore chunked while the request is still being received, and the case asserts that the client's response body may have trailers and has no length. Over HTTP/1.0 it asserts a close-delimited echo. A sabotaged route that echoes with the request's length fails it over both versions at "the echo's framing".duplex_streamlikewise asserts that its echo carries the request's length and no trailers.Trailerfield to choose framing. #50, a known-length request is sent withContent-Lengthand its trailers are dropped, so both cases upload a plainBodyReaderover either version. Neither case streams a chunked request.duplex_datacopies a constant 251-byte period instead of computing each byte, because per-byte work made the parallel two-way cases exceed the 10 s test timeout under coverage instrumentation.crates/client/tests/protocol.rsruns the protocol and trailer suites in spawned mode, as well as scoped, over HTTP/1.1, HTTP/1.0, where the trailer cases check that trailers are dropped, and HTTPS.design/fixtures.mdgains a "Spawned server context" requirement and extends the raw peer and behaviour suite requirements.Limitations
run_spawnedshuts its scheduler down, and Native drains every task. The call therefore doesn't return until an overrunning server's current poll returns. A poll that never returns can't be preempted and hangs the test after the failure is reported. This is stated in therun_spawneddocs and indesign/fixtures.md.releases.mdentry.🤖 Generated with Claude Code