Repository navigation
test: drip server closes the mid-response streaming coverage gaps - #186
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## bounded-admission-timeout #186 +/- ##
=============================================================
+ Coverage 78.23% 78.52% +0.29%
=============================================================
Files 9 9
Lines 1369 1369
=============================================================
+ Hits 1071 1075 +4
+ Misses 298 294 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
puzza007
force-pushed
the
bounded-admission-timeout
branch
from
July 18, 2026 08:49
a83b638 to
47b9148
Compare
puzza007
force-pushed
the
drip-test-server
branch
from
July 18, 2026 08:49
0406ae3 to
9b72d9a
Compare
puzza007
force-pushed
the
bounded-admission-timeout
branch
from
July 18, 2026 08:59
47b9148 to
ba12838
Compare
puzza007
force-pushed
the
drip-test-server
branch
from
July 18, 2026 08:59
9b72d9a to
eccf168
Compare
puzza007
force-pushed
the
bounded-admission-timeout
branch
from
July 18, 2026 09:05
ba12838 to
170d439
Compare
puzza007
force-pushed
the
drip-test-server
branch
from
July 18, 2026 09:05
eccf168 to
a52ae7f
Compare
puzza007
force-pushed
the
bounded-admission-timeout
branch
from
July 18, 2026 09:09
170d439 to
9261944
Compare
puzza007
force-pushed
the
drip-test-server
branch
from
July 18, 2026 09:09
a52ae7f to
6dc47b9
Compare
…llers
The admission handshake introduced with the exactly-once dispatch work
used an infinity gen_server:call, so a wedged worker -- typically its C
port stopped draining the pipe and port_command blocked the worker
mid-callback -- silently absorbed async_req callers with no bound at
all. Admission is a port write plus a map insert (microseconds when
healthy), so bound the call at 5s: a worker that cannot answer in time
yields an immediate {error, #{code => admission_timeout}} and the caller
can retry, re-rolling onto a healthy random worker, instead of blocking
indefinitely. A request the worker admits after the caller gave up is
cleaned up by its own request timer.
The bound applies only to the async admission ack and is derived from
the message kind in one place (admission_bound/1): a synchronous
request's single call carries the whole response -- the worker replies
when the transfer or its request timer completes -- so it stays
unbounded at the call layer and is governed by the request timeout as
before. attempt/2 guards its timeout mapping on the bound, since on an
unbounded call a {timeout, _} exit can only be a worker that died with
that exit reason. The fail-fast contract is uniform: a timeout during
overload-spillover also returns immediately, so an admission waits at
most one bound, never one per candidate.
Deterministic coverage in katipo_async_failure_SUITE: a suspended
worker (the messages-queue-but-nothing-runs shape of the production
wedge) must produce admission_timeout within the bound. 199 tests,
dialyzer, xref, and lint pass.
The local httpbin stack buffers whole responses behind its proxy, so two streaming behaviors were only reachable in the TLA+ model, never against a real socket: a terminal error arriving after chunks, and a cancel landing between headers and done. katipo_drip_server is a minimal single-connection HTTP/1.1 responder that makes both deterministic: it can advertise more Content-Length than it sends (close -> partial_file mid-body), deliver timed body pieces so a response is genuinely in progress, stall with the socket open, and report peer-close to the owning test. Three new cases: streaming_error_mid_body (headers, at least one chunk, then partial_file), streaming_timeout_mid_body (headers and a chunk, then operation_timedout while stalled), and streaming_cancel_mid_stream -- which also asserts the stalled server's recv observes the connection close after the cancel, the end-to-end proof that the C port aborts the transfer rather than merely having its late output dropped, covering cancel_conn against a live socket for the first time. The suite gains expect_stream_headers/expect_first_chunk helpers shared by the new tests and streaming_flow_control's previously inline receives, and the cancelled-stream silence check drains in-flight chunks then delegates to the existing assert_stream_stopped contract helper. 202 tests, dialyzer, xref, and lint pass.
puzza007
force-pushed
the
bounded-admission-timeout
branch
from
July 18, 2026 09:37
9261944 to
bec37ad
Compare
puzza007
force-pushed
the
drip-test-server
branch
from
July 18, 2026 09:38
6dc47b9 to
e14096b
Compare
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.
The local httpbin stack buffers whole responses behind its proxy, so two streaming behaviors have been test-blind since the streaming work landed — reachable only in the TLA+ model, never against a real socket: a terminal error arriving after chunks were already delivered, and a cancel landing between headers and done. Both were disclosed as accepted gaps in #182.
katipo_drip_server closes them: a ~90-line single-connection HTTP/1.1 responder that can advertise a larger Content-Length than it sends (closing early yields a deterministic partial_file mid-body), deliver timed body pieces so a response is genuinely in progress when the interesting event happens, stall with the socket open, and report peer-close to the owning test. It's linked to the test process, so failures tear it down.
Three new cases in the async group. streaming_error_mid_body: headers, at least one chunk, then the terminal partial_file — the error-after-chunks sequencing previously only model-verified. streaming_timeout_mid_body: headers and a chunk, then operation_timedout while the server stalls. And streaming_cancel_mid_stream, the strongest of the set: after a cancel between headers and done, in-flight chunks may drain but no terminal message ever arrives — and the stalled server's recv observes the connection close, the end-to-end proof that cancel_conn in the C port actually aborts the transfer rather than merely having its late output dropped. That C path had never been exercised against a live socket.
The suite also gains expect_stream_headers/expect_first_chunk helpers shared with the previously inline receives in streaming_flow_control. 202 tests, dialyzer, xref, and lint pass.
Top of the stack: #180 → #182 → #183 → #184 → #185 → this. Merge bottom-up; I'll rebase each layer as the one below lands.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Vf2gxZLpxT4HvBfZKCgP3g