harness: the producer/consumer integration test harness over duplex
tests/harness.rs — the producer<->consumer wiring over one tokio::io::duplex carrying the channels 8-byte chunk format, the alkcall 0.8.0 establishment surface consumed for the first time by this crate (register_openable_with_establisher + the call/adopt dance) — the first-consumption risk retired. - Identities: consumer (socks5:open) / bind (socks5:bind only) / both-scopes (explicit, ADR-006) + TestIdProvider (token path). - In-process seams, no sockets, no `local`: echo_dial / refusing_dial (variant-preserving), echo_egress (readiness contract verified — next_reply parks Pending when idle) / refusing_egress, echo_accept / refusing_accept_factory / refusing_accept (two-stage BIND refusal shapes, mapped through to_reply_error()). - Producer-side registration helper: register_socks5_openable_minimal + socks5_session_establisher + RegisterMode — the single place the producer wiring lives; the CF-006 identity witness rides it and is asserted end-to-end. - RawRfcClient: the hand-rolled RFC 1928 client helper over any AsyncRead + AsyncWrite, round-tripped against a byte-level hand-rolled server (success + refusal replies). - Smoke test: harness up -> producer registered -> consumer open + adopt -> raw RFC CONNECT -> echo round-trip through pump_bidi. Fail-closed probe: scope-less identity -> FORBIDDEN, no channel anywhere (the load-bearing POC #1 set_identity wiring requirement, explicit in the install hook and tested). 14 harness tests. Verification: cargo test (127 green), clippy (all-targets + wasm32) clean, fmt clean, doc zero warnings, test --all-features green, both wasm checks clean (harness is dev-only).
This commit is contained in:
1 parent
ac361f7610
commit
f8773521b9
2 files changed
+1275
-9
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: implementation/core-test-harness
|
||||
name: Core — integration test harness (duplex transport + identities + in-process seams)
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: [implementation/core-seam-types, implementation/core-params-errors]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
@@ -81,16 +81,16 @@ Deliverables:
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Harness topology works over alkcall 0.8.0 (the establishment
|
||||
- [x] Harness topology works over alkcall 0.8.0 (the establishment
|
||||
surface consumed successfully — the first-consumption risk
|
||||
retired)
|
||||
- [ ] Identity wiring explicit: `set_identity` in the install hook;
|
||||
- [x] Identity wiring explicit: `set_identity` in the install hook;
|
||||
a scope-less identity gets `FORBIDDEN` (fails closed) — tested
|
||||
- [ ] All three identities + all in-process seam closures unit-tested
|
||||
- [ ] The raw RFC client helper round-trips a greeting + command +
|
||||
- [x] All three identities + all in-process seam closures unit-tested
|
||||
- [x] The raw RFC client helper round-trips a greeting + command +
|
||||
reply against a hand-rolled server over a duplex
|
||||
- [ ] No `local` feature, no sockets — everything in-process
|
||||
- [ ] `cargo test` green; clippy/fmt clean; both wasm checks clean
|
||||
- [x] No `local` feature, no sockets — everything in-process
|
||||
- [x] `cargo test` green; clippy/fmt clean; both wasm checks clean
|
||||
(the harness is dev-only — verify it stays out of the wasm
|
||||
build)
|
||||
|
||||
@@ -108,8 +108,108 @@ Deliverables:
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
> Filled by the implementation agent (2026-09-23).
|
||||
|
||||
- `tests/harness.rs`: the producer↔consumer wiring over one
|
||||
`tokio::io::duplex` carrying the channels 8-byte chunk format, in
|
||||
the task's topology — **producer = connect side**
|
||||
(`ChannelClient::from_connection_with_serving`; its manager
|
||||
allocates the odd channel IDs), **consumer = accept side** (the
|
||||
`ChannelsAdapter` + capturing install hook; the hook captures the
|
||||
consumer's channel-0 `CallConnection` + `ChannelManager`).
|
||||
- The load-bearing POC #1 wiring requirement is explicit and tested:
|
||||
the hook calls `channel0_conn.set_identity(resolved)` before
|
||||
building the `CallConnection`; the transport identity is set on
|
||||
the dialing (producer) connection before
|
||||
`from_connection_with_serving` (CF-005 (b) primary path). The
|
||||
scope-less identity test asserts the `FORBIDDEN` code and that no
|
||||
channel survives on either side (fail-closed).
|
||||
- Identities: `consumer_identity()` (`socks5:open` only),
|
||||
`bind_identity()` (`socks5:bind` only), `both_scopes_identity()`
|
||||
(both, explicit — ADR-006), `TestIdProvider` +
|
||||
`TEST_AUTH_TOKEN` (the token-resolver path, unit-tested both
|
||||
directions).
|
||||
- In-process seams (no sockets, no `local`): `echo_dial()`
|
||||
(echo-per-dial, exercised through `pump_bidi` — the producer data
|
||||
plane's shape), `refusing_dial(err)` (variant-preserving per-call
|
||||
reconstruction — the seam errors are not `Clone`),
|
||||
`echo_egress()` (a `ChanEgress` whose `next_reply` parks on
|
||||
`mpsc::UnboundedReceiver::recv()` — `Pending` when idle, the
|
||||
readiness contract verified with a 50ms timeout probe),
|
||||
`refusing_egress(err)`, `echo_accept()` (reply#1 advertises a
|
||||
static in-process BND.ADDR, `ECHO_BIND_PORT` 2121; the accept
|
||||
future resolves immediately with echo-pipe halves),
|
||||
`refusing_accept_factory(err)` (pre-reply#1) and
|
||||
`refusing_accept(err)` (post-reply#1).
|
||||
- `register_socks5_openable_minimal` + `socks5_session_establisher`:
|
||||
the producer-side wiring helper over alkcall 0.8.0's
|
||||
`ChannelCore::register_openable_with_establisher` (spec from
|
||||
`socks5_open_spec()`, `Establishment::default()` — session gate
|
||||
only; the dial is in-stream). The establisher witnesses the
|
||||
per-call opener identity id (CF-006) into an `IdentityWitness`,
|
||||
asserted end-to-end in the smoke test.
|
||||
- `RegisterMode` (`MinimalConnect(dial)` / `NoSocks5`) controls what
|
||||
`wire_with` registers post-hoc (W2) on the producer's serving
|
||||
registry; generic channel ops always register.
|
||||
- The smoke test's producer path is the minimal CONNECT stand-in
|
||||
(`make_minimal_connect_handler` → `serve_connect_minimal`: the
|
||||
forked typestate's `accept_no_auth` → `read_command` → CONNECT-only
|
||||
dispatch → the injected `DialFn` → `reply_success` → `pump_bidi`
|
||||
inline, R-02). The producer task replaces this; the registration
|
||||
shape (spec/establisher/handler/auth/timeout) stays.
|
||||
- `RawRfcClient<S>`: hand-rolled greeting (`05 01 00` → `05 00`) +
|
||||
request encoder (all three commands, all address forms via
|
||||
`TargetAddr::to_be_bytes()`) + reply reader (v4/v6/domain BND.ADDR
|
||||
forms; returns `(code, addr_bytes)`). Round-trip-tested against a
|
||||
hand-rolled byte-level server over a duplex, success + refusal
|
||||
reply codes; the harness is producer-independent (no consumer
|
||||
session types).
|
||||
- Wire note: the smoke test calls the open op via
|
||||
`consumer_call.call(OP_SOCKS5_OPEN, Socks5Params::as_json())` and
|
||||
adopts on `consumer_manager` (the alktunnels `wire_with` +
|
||||
`open_reverse_channel` shape) rather than
|
||||
`ChannelClient::open_channel` — in this topology the open op is
|
||||
served by the producer's registry and reached from the accept
|
||||
side's channel-0 call surface; `open_channel` remains the
|
||||
consumer-session surface for the consumer task's session types.
|
||||
- The harness is `tests/harness.rs` only (dev-only) — verified out
|
||||
of the wasm build by the targeted checks below.
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
> Filled on completion (2026-09-23).
|
||||
|
||||
Built `tests/harness.rs` — the integration test harness: the
|
||||
producer↔consumer topology over one `tokio::io::duplex` (producer =
|
||||
connect side/serving; consumer = accept side/adapter + capturing
|
||||
hook), the alkcall 0.8.0 establishment surface consumed for the
|
||||
first time by this crate (`register_openable_with_establisher`,
|
||||
`Establishment::default`, the consumer-side call + adopt dance) —
|
||||
the first-consumption risk retired with 14 green tests.
|
||||
|
||||
- The three identities + `TestIdProvider` (all unit-tested).
|
||||
- All in-process seam closures: `echo_dial`/`refusing_dial` (variant-
|
||||
preserving), `echo_egress` (readiness contract verified — a 50ms
|
||||
timeout probe proves `next_reply` parks, never a hot `Ok(None)`) /
|
||||
`refusing_egress`, `echo_accept` (immediate resolve + echo) /
|
||||
`refusing_accept_factory` / `refusing_accept` (two-stage refusal
|
||||
shapes, mapping-table-verified through `to_reply_error()`).
|
||||
- The producer registration helper (`register_socks5_openable_minimal`
|
||||
+ `socks5_session_establisher` + `RegisterMode`) — the single place
|
||||
the producer-side wiring lives; the CF-006 identity witness rides
|
||||
it and is asserted.
|
||||
- `RawRfcClient` — the raw RFC 1928 client helper over any
|
||||
`AsyncRead + AsyncWrite`, round-tripped against a hand-rolled
|
||||
byte-level server (success + refusal replies).
|
||||
- The smoke test: harness up → producer registered → consumer open +
|
||||
adopt → raw RFC CONNECT → echo round-trip through `pump_bidi`, with
|
||||
the establisher witness asserted mid-flight. Plus the fail-closed
|
||||
probe (scope-less identity → `FORBIDDEN`, no channel anywhere) and
|
||||
the odd-ID allocation/adopt sanity probe.
|
||||
|
||||
Verification: `cargo test` (127 green: 76 lib + 14 harness + 37
|
||||
rfc1928-differential), `cargo test --all-features` green, `cargo
|
||||
clippy --all-targets -- -D warnings` clean, `cargo fmt --check`
|
||||
clean, `cargo doc --no-deps` zero warnings, both wasm checks
|
||||
(`cargo check` + `cargo clippy` on `wasm32-unknown-unknown`) clean —
|
||||
the harness stays out of the wasm build.
|
||||
+1166
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user