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).
11 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | ||
|---|---|---|---|---|---|---|---|---|---|
| implementation/core-test-harness | Core — integration test harness (duplex transport + identities + in-process seams) | completed |
|
moderate | medium | phase | implementation |
Description
Build tests/harness.rs — the producer↔consumer wiring over a
tokio::io::duplex carrying the channels 8-byte chunk format — so
every subsequent core task tests end-to-end without the local
feature. This is the alkcall-0.8.0-first-consumption task: the POCs
ran 0.7.1; the harness proves the 0.8.0 establishment surface
(register_openable_with_establisher, Establishment,
ChannelClient::open_channel) works for this crate's shape before
the producer task builds on it. Template:
/workspace/@alkdev/alktunnels/tests/harness.rs (the sibling's
harness — same topology, adapted to this crate's seams).
Topology (the alktunnels harness shape):
- producer (connect side of the channels connection — runs
ChannelClient::from_connection_with_serving): serves the socks5 open op + generic channel ops on its serving registry. Its manager allocates the channel IDs (ChannelSide::Connect— the serving side allocates; the initiator adopts). - consumer (accept side): the
ChannelsAdapter+ capturing install hook. The hook captures the consumer's channel-0CallConnectionandChannelManager. - The POC #1 wiring requirement is load-bearing here (producer.md
§Harness wiring requirement): the accept-side install hook must
call
channel0_conn.set_identity(resolved)before building theCallConnection— without it, scope-gated opens fail closed withFORBIDDEN "authentication required"(correct behavior, implicit wiring). The harness makes the requirement explicit and tested.
Deliverables:
- Identities:
consumer_identity()(socks5:openonly),bind_identity()(socks5:bindonly — the command-gate probe),both_scopes_identity()(both grants, explicitly — never implied, ADR-006), plus aTestIdProviderresolving them (the alktunnels harness shape). - In-process seam closures (no sockets — the protocol layer is
substrate-agnostic, so the harness dials in-process):
echo_dial()— aDialFnreturning duplex-halves wired to an in-process echo server (the POC #1 shape); plusrefusing_dial()(a failing dial for the refusal-mapping tests).echo_egress()— anEgressFactorywhose egress echoes datagrams back (the POC #2 shape, readiness-contract-clean: parks on a channelrecv(),Pendingwhen nothing is ready).echo_accept()— aBindAcceptFactorywhose accept resolves immediately with in-process halves (the POC #5 shape); plus a failing variant.
- The producer registration helper: a
spawn_producer(...)function wiringregister_socks5_openable(or its task-6 successor) with the harness seams — the single place the producer-side wiring lives, so the per-command tasks only write tests. - A raw RFC client helper: a hand-rolled minimal RFC 1928
client over any
AsyncRead + AsyncWrite(greeting → method selection → command with target → reply read) — the differential suite's established pattern — so producer tasks test without depending on the consumer session types (which land later). - One smoke test proving the full loop: harness up → producer
registered → consumer opens a channel → raw RFC CONNECT
conversation → echo round-trip. (This test needs a minimal
CONNECT producer path; if the producer task hasn't landed, stub
the handler with the POC #1
serve_socks5_overshape inline in the harness — the producer task then replaces it. Alternatively sequence this task to land immediately before the producer task and let the smoke test be the producer task's first test — the implementer's judgment; the acceptance bar is the harness compiling with the identities + seams + helpers tested.)
Acceptance Criteria
- Harness topology works over alkcall 0.8.0 (the establishment surface consumed successfully — the first-consumption risk retired)
- Identity wiring explicit:
set_identityin the install hook; a scope-less identity getsFORBIDDEN(fails closed) — tested - All three identities + all in-process seam closures unit-tested
- The raw RFC client helper round-trips a greeting + command + reply against a hand-rolled server over a duplex
- No
localfeature, no sockets — everything in-process cargo testgreen; clippy/fmt clean; both wasm checks clean (the harness is dev-only — verify it stays out of the wasm build)
References
- Template:
/workspace/@alkdev/alktunnels/tests/harness.rs(the topology + identity shapes) - POC harnesses:
/workspace/alksocks-connect-poc/src/harness.rs,/workspace/alksocks-udp-poc/src/harness.rs,/workspace/alksocks-bind-poc/src/harness.rs - docs/architecture/producer.md §Harness wiring requirement (the
set_identityrequirement) - docs/architecture/decisions/006-access-control.md (the scope identities)
Notes
Filled by the implementation agent (2026-09-23).
tests/harness.rs: the producer↔consumer wiring over onetokio::io::duplexcarrying 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 (theChannelsAdapter+ capturing install hook; the hook captures the consumer's channel-0CallConnection+ChannelManager).- The load-bearing POC #1 wiring requirement is explicit and tested:
the hook calls
channel0_conn.set_identity(resolved)before building theCallConnection; the transport identity is set on the dialing (producer) connection beforefrom_connection_with_serving(CF-005 (b) primary path). The scope-less identity test asserts theFORBIDDENcode and that no channel survives on either side (fail-closed). - Identities:
consumer_identity()(socks5:openonly),bind_identity()(socks5:bindonly),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 throughpump_bidi— the producer data plane's shape),refusing_dial(err)(variant-preserving per-call reconstruction — the seam errors are notClone),echo_egress()(aChanEgresswhosenext_replyparks onmpsc::UnboundedReceiver::recv()—Pendingwhen 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_PORT2121; the accept future resolves immediately with echo-pipe halves),refusing_accept_factory(err)(pre-reply#1) andrefusing_accept(err)(post-reply#1). register_socks5_openable_minimal+socks5_session_establisher: the producer-side wiring helper over alkcall 0.8.0'sChannelCore::register_openable_with_establisher(spec fromsocks5_open_spec(),Establishment::default()— session gate only; the dial is in-stream). The establisher witnesses the per-call opener identity id (CF-006) into anIdentityWitness, asserted end-to-end in the smoke test.RegisterMode(MinimalConnect(dial)/NoSocks5) controls whatwire_withregisters 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'saccept_no_auth→read_command→ CONNECT-only dispatch → the injectedDialFn→reply_success→pump_bidiinline, 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 viaTargetAddr::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 onconsumer_manager(the alktunnelswire_with+open_reverse_channelshape) rather thanChannelClient::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_channelremains the consumer-session surface for the consumer task's session types. - The harness is
tests/harness.rsonly (dev-only) — verified out of the wasm build by the targeted checks below.
Summary
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 provesnext_replyparks, never a hotOk(None)) /refusing_egress,echo_accept(immediate resolve + echo) /refusing_accept_factory/refusing_accept(two-stage refusal shapes, mapping-table-verified throughto_reply_error()). - The producer registration helper (
register_socks5_openable_minimalsocks5_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 anyAsyncRead + 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.