- forward_stream build-error arm (forward.rs): wire-level test asserts one INVALID_INPUT envelope then stream end with zero upstream contact (a panicking responder counts as the contact guard), plus the from_jsonschema integration mirror (undeclared key + non-scalar placeholder, each naming its rejection source) - PEM read-failure arms (http_client.rs): nonexistent CA path → CaBundleRead (sync new), nonexistent client-cert path → ClientCertRead (async reload, prior generation retained) - Over-cap poll_write rejection leg (byte_adapter.rs): cap+1 write → InvalidData naming the cap; stream stays usable for an at-cap write afterwards - SSE parser edges: CRLF split across feed chunks frames one line; invalid-UTF8 data lines drop without killing the frame stream - from_value structural rejects: non-object doc, missing `info`, missing `paths`, non-object `paths` each name the member - Connection-failure arms: accept-path ConnectionClosed → HandlerError::ConnectionClosed via stream_error_to_handler; read-pump demux-gone break ends the pump when the byte-stream side is dropped - Delete the caller-less `impl Default for WsTimeouts` (the extension is constructed explicitly) cargo llvm-cov --all-features: all named arms covered; TOTAL regions 94.18% (was 93.86%), lines 96.04% (was 95.77%); http_client.rs 86.56% lines (was 81.72%). docs(tasks): mark review-002-fu-stream-error-coverage done
5.2 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| review-002-fu-stream-error-coverage | Streaming error-arm coverage — forward_stream invalid input, PEM read-failure, over-cap poll_write mirror (post-bulk coverage gap) | done | narrow | low | component | implementation |
|
Description
Bracketed follow-up discovery from the post-bulk coverage re-pass (95.89% regions overall; the review-002 bulk's own new code verified fully covered — PRJ-16 guard, body cap, router reorder, batch cap, WS-13/18/19, the OAI-11 memo node-budget all exercised). The residue is small but one item matters more than its line count:
forward_streambuild-request error arm (forward.rs:1085-1090): a Sub op invoked with an invalid input (undeclared key, non-scalar placeholder value) must produce exactly one error envelope from the stream — the streaming analog of the Once-path error handling. No test drives it: every SSE test (from_jsonschemaintegration_sse_subscription…, forward.rs's stream family) sends valid input. A regression returning an empty stream (silently swallowing the error) would be invisible — and an empty-200-subscribe is the worst failure shape for a subscriptions consumer.- PEM read-failure arms (http_client.rs CaBundleRead/ClientCertRead,
sync + async): the parse-failure arms are covered
(
corrupt_ca_bundle_fails_ca_bundle_parse_with_path,garbage_client_cert_fails_…in client_tls.rs, landed in6490d15), but the unreadable-file arms (nonexistent path, unreadable permissions) have no test on either build path. The error taxonomy half-documented atHttpClientBuildError's doc block (:214) is half-specified. - Over-cap
poll_writerejection (byte_adapter.rs:789-798): WS-14's moved check rejects writes abovePENDING_BUFFER_CAPwithInvalidDatabefore entry to the queue — the "at cap" boundary is tested (tungstenite_write_at_the_cap_is_accepted, 1158) and the framing-level cap-trip is tested both flavors (axum_framing_cap_trip…), but the single-call over-cap rejection itself (the WS-14 acceptance test's own criterion) never runs: no test writesPENDING_BUFFER_CAP + 1. forward_streamSSE-parser residual edges: split-CRLF-across- chunks (the\r+"\n…"case), invalid-UTF8-line drop — the parser edges the bulk's stream arms work next to.from_valuestructural rejections (openapi_spec.rs:391-398, 416-418): a non-object document, a missing-info, a non-objectpaths— none ever exercised (all other structural rejects are).- Connection-failure arms:
protocol_handleraccept-pathstream_error_to_handler(adapter.rs:597-599) and the read-pump demux-gonebreak(byte_adapter.rs:374-381) — both are connection-failure semantics with zero direct coverage. - Dead-ish:
impl Default for WsTimeouts(upgrade.rs:344-351) has zero callers (the extension is constructed explicitly in the one test that uses it) — delete or#[allow(dead_code)]with the reason.
Acceptance Criteria
- Wire test: Sub op + undeclared key (or non-scalar placeholder
value) → the subscriber receives exactly one
INVALID_INPUTenvelope and the stream ends (upstream receives zero requests) - Two PEM read-failure tests:
SharedHttpClient::newwith a nonexistent CA path →CaBundleReadcarrying the path;reloadwith a nonexistent client-cert path →ClientCertRead - One over-cap
poll_writetest:write_all(PENDING_BUFFER_CAP+1)→InvalidDataerror naming the cap (asserts the WS-14 moved check's rejection leg; the = cap test exists) - SSE parser edge tests: CRLF split across chunks (
…\rends chunk 1,\n…opens the next), invalid-UTF8 line dropped - from_value structural tests: non-object doc, missing-
info, non-objectpaths→SchemaParsenaming the missing member WsTimeoutsredundantDefaultdeleted (or justified+allowed)cargo llvm-cov --all-features: named arms no longer dark;cargo test --all-features, clippy, fmt pass
References
- docs/reviews/002-post-remediation-review.md (Part G' test-gaps; post-bulk re-analysis finding list)
- src/adapters/forward.rs:1085-1090 (stream build-error arm), src/client/http_client.rs:484-545 (read-failure arms), src/websocket/byte_adapter.rs:789-798 (over-cap poll_write)
- tests/client_tls.rs (the PEM harness: parse-failure tests at :226-448 are the pattern to mirror for read-failures)
- tasks/infra/review-002-cov-deployment-knobs.md (the pre-bulk coverage task these extend)
- tasks/infra/review-002-cov13-dead-code.md (the dead-code convention for the WsTimeouts Default)
Notes
Tests-only + one deletion. The streaming-build-error test's
load-bearing assertion is the single envelope then end semantics —
mirror oversized_upstream_sse_line_terminates_with_one_internal_envelope's
assert structure but trigger pre-send instead (invalid input, no
responder needed for the reject case — wire it against a live-responder
anyway if the harness makes it cheap; the zero-upstream-contact assert
is the point). The spawn_responder-family harnesses in
forward.rs/from_jsonschema.rs cover the seam.