feat(runtime): in-process module test harness over the mock assembly#203
Open
mfw78 wants to merge 1 commit into
Open
feat(runtime): in-process module test harness over the mock assembly#203mfw78 wants to merge 1 commit into
mfw78 wants to merge 1 commit into
Conversation
TestRuntime wraps the public builder path over the mock lattice: it opens one module from a wasm path plus a manifest (a path, or inline TOML temp-filed at launch), installs a manually-driven clock, and returns a handle bundling the running RuntimeHandle with the retained mock backends. A test programs chain responses, injects block headers and chain logs, advances the clock, reads what a module wrote, and reads runs and log pages, then shuts down and waits. The extension slot is the lattice type parameter (MockTypes now carries an Ext payload, defaulting to the empty slot), so an extension crate drives its backend through the same harness by passing an ext payload and its extensions. A trivial in-tree extension proves the threading. Port the host-interface-records supervisor e2e test onto the harness to lock the ergonomics, holding the original coverage.
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.
Summary
Closes #199; part of the epic #80 train, merges in stack order.
Adds a
TestRuntime/TestRuntimeBuilderharness intest_utilsthat launches one module over the mock assembly through the publicRuntimeBuilderpath, replacing the hand-builtEngineConfigplusboot_singleplus manualevent_loop::runceremony that today's supervisor e2e tests repeat.Changes
crates/nexum-runtime/src/test_utils/harness.rs:TestRuntimeandTestRuntimeBuilderover the mock assembly.The builder takes a wasm path plus a manifest (
manifest_pathormanifest_inline, temp-filed at launch), optional extensions, and an ext payload.Pre-launch accessors (
chain/store/clock) let a caller program the mocks before the module starts.The launched handle bundles the
RuntimeHandlewith the retainedMockChainProvider,MockStateStore,ManualClock, and ext payload, and exposespush_block/push_chain_log,logs(),ext(), await_for_logpoll helper that doubles as the dispatch barrier, andshutdown/wait.crates/nexum-runtime/src/test_utils/types.rs:MockTypesgeneralised toMockTypes<E = ()>so the ext slot is the lattice type parameter (the()default preserves every existing call site).crates/nexum-runtime/src/test_utils/mod.rs: registerspub mod harnessand re-exportsTestRuntime/TestRuntimeBuilder.crates/nexum-runtime/src/supervisor/tests.rs:host_interface_records_are_retrievable_after_a_runported onto the harness (inline-manifest launch plus injected header plus polled log read, replacing theboot_singleplus manualdispatch_blockceremony), with the same assertions.crates/nexum-runtime/Cargo.toml:test-utils = ["dep:tempfile"], withtempfilepromoted from a dev-only dependency to an optional one, since the harness ships in the library gated behind the feature.Test plan
cargo fmt --all --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-features(all pass, including doctests; new testsharness_launches_dispatches_and_reads_logsandharness_threads_an_extension_and_ext_payloadpass, and the portedhost_interface_records_are_retrievable_after_a_runpasses with the same assertions as before)RUSTDOCFLAGS="-D warnings" cargo doc -p nexum-runtime --all-features --no-deps--no-default-featuresclippy stays clean, so the harness andtempfiledo not compile into the bare default buildNotes for reviewer
The harness composes over the public
RuntimeBuilderbuilder methods (with_types,with_extensions,with_module_source,with_wasi_clocks,with_components,with_add_ons) rather than reaching into the supervisor internals, so events dispatch through the real spawned event loop.One consequence: a test injects a header and awaits an observable effect rather than reading a dispatch count, so
wait_for_logpolls the log pipeline (a 2ms-cadence sleep that yields to the event-loop task on both runtime flavours) and acts as the barrier proving the block was dispatched.MockTypesbecoming generic overElets the same harness carry a real extension payload, sinceExtension<MockTypes<E>>and the components'ext: Eslot both key off it.Two entry points keep this ergonomic without type-state:
TestRuntime::builder(wasm)for the()case, andTestRuntime::builder_with_ext(wasm, ext)for the extension case, since extensions depend onEand soEmust be fixed up front.The trivial-extension proof uses a no-op linker hook (asserted to have run at boot via an
AtomicUsize) and an emptyNamespaceCaps { prefix: "test:ext/", ifaces: &[] }, plus anArc<AtomicUsize>ext payload the harness hands back viaext().No custom WIT guest is needed; it proves the extension and ext payload thread through and the module still boots and dispatches under the extension-bearing lattice.
Follow-ups noted but out of scope here: a harness helper for chain-log dispatch assertions (only the block leg is locked today), swapping
wait_for_log's wall-clock poll for a deterministic barrier, and porting the remainingboot_single-shaped e2e tests (multi-chain isolation, poison-pill, restart-backoff) once the harness grows a multi-module builder variant.AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.