Add MVP_SYSTEM_SPEC plus per-component contract docs (arena manager, device bridge, gpu worker ctl/ingress/egress/process-adapter, orchestrator run-fsm/token-endpoint, run plan, stage controller, tx_rx edge, weights). Scaffold the guarantee tests against the (empty) mvp-system crate. Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
259 lines
10 KiB
Rust
259 lines
10 KiB
Rust
//! Black-box contract tests for MVP driver and pump behavior.
|
|
//!
|
|
//! These tests intentionally know only the public driver surface:
|
|
//!
|
|
//! - establish-send/recv, incoming stream, wake, stop, and I/O outcomes in
|
|
//! - stream opens, ring cursor updates, wake hints, faults, and stopped events out
|
|
//!
|
|
//! They assert the guarantees in
|
|
//! `specs/mvp_system/driver_pumps_contract.md`.
|
|
|
|
use mvp_system::driver_pumps as driver;
|
|
|
|
// A driver config names one endpoint and one ALPN. Tests do not expose tokio
|
|
// tasks, connection internals, or stream futures to actors.
|
|
fn driver_config() -> driver::DriverConfig {
|
|
driver::DriverConfig {
|
|
local_node_id: driver::NodeId(10),
|
|
alpn: driver::Alpn("swactor-edge-mvp".into()),
|
|
}
|
|
}
|
|
|
|
// A send spec describes one persistent uni-stream for one edge to one peer.
|
|
// The pump still owns when and how bytes leave the egress ring.
|
|
fn send_spec() -> driver::EstablishSend {
|
|
driver::EstablishSend {
|
|
edge_id: driver::EdgeId(7001),
|
|
peer_node_id: driver::NodeId(11),
|
|
layout: driver::RingLayout::test_egress(),
|
|
}
|
|
}
|
|
|
|
// A recv spec describes one edge and one ingress ring. It may arrive before or
|
|
// after the network stream, which is the receive rendezvous guarantee.
|
|
fn recv_spec() -> driver::EstablishRecv {
|
|
driver::EstablishRecv {
|
|
edge_id: driver::EdgeId(7001),
|
|
layout: driver::RingLayout::test_ingress(),
|
|
}
|
|
}
|
|
|
|
// The harness gives tests mock stream and ring observations while keeping the
|
|
// driver as the owner of demux and byte-pump behavior.
|
|
fn new_driver() -> driver::DriverHarness {
|
|
driver::DriverHarness::new(driver_config())
|
|
}
|
|
|
|
// This helper extracts the byte transcript for a stream. It proves preamble and
|
|
// object bytes by observing writes accepted by the mock stream, not by peeking
|
|
// into pump internals.
|
|
fn written_bytes(harness: &driver::DriverHarness, edge_id: driver::EdgeId) -> Vec<u8> {
|
|
harness
|
|
.stream_writes(edge_id)
|
|
.iter()
|
|
.flat_map(|write| write.bytes.clone())
|
|
.collect()
|
|
}
|
|
|
|
// This proves the driver owns endpoint, connection cache, ALPN, stream demux,
|
|
// and send/recv pump tasks, while actors do not poll stream futures directly.
|
|
#[test]
|
|
fn driver_owns_endpoint_connection_demux_and_pump_tasks() {
|
|
// Create the driver and establish a send edge.
|
|
let mut harness = new_driver();
|
|
harness.observe(driver::DriverEvent::EstablishSend(send_spec()));
|
|
|
|
// The driver creates or reuses a connection under its endpoint and ALPN.
|
|
assert!(harness.commands().iter().any(|command| {
|
|
matches!(
|
|
command,
|
|
driver::DriverCommand::OpenOrReuseConnection {
|
|
peer_node_id: driver::NodeId(11),
|
|
alpn: driver::Alpn(ref value),
|
|
..
|
|
} if value == "swactor-edge-mvp"
|
|
)
|
|
}));
|
|
|
|
// Pump tasks are driver-owned.
|
|
assert!(harness.commands().iter().any(|command| {
|
|
matches!(command, driver::DriverCommand::SpawnSendPump { edge_id: driver::EdgeId(7001), .. })
|
|
}));
|
|
|
|
// Actor commands must not expose stream polling.
|
|
assert!(!harness.actor_messages().iter().any(|message| {
|
|
matches!(message, driver::ActorMessage::PollStreamFuture { .. })
|
|
}));
|
|
}
|
|
|
|
// This proves each edge uses one persistent uni-stream, writes an edge-id
|
|
// preamble once, carries object records as bytes after the preamble, and does
|
|
// not open one stream per object.
|
|
#[test]
|
|
fn send_stream_is_persistent_with_single_edge_preamble() {
|
|
// Establish one send edge and make two committed egress records readable.
|
|
let mut harness = new_driver();
|
|
harness.observe(driver::DriverEvent::EstablishSend(send_spec()));
|
|
harness.observe(driver::DriverEvent::EgressBytesCommitted {
|
|
edge_id: driver::EdgeId(7001),
|
|
bytes: b"obj0".to_vec(),
|
|
});
|
|
harness.observe(driver::DriverEvent::RingReadable {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
harness.observe(driver::DriverEvent::EgressBytesCommitted {
|
|
edge_id: driver::EdgeId(7001),
|
|
bytes: b"obj1".to_vec(),
|
|
});
|
|
harness.observe(driver::DriverEvent::RingReadable {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
|
|
// Only one stream is opened for the edge.
|
|
let stream_opens = harness
|
|
.commands()
|
|
.iter()
|
|
.filter(|command| matches!(command, driver::DriverCommand::OpenUniStream { .. }))
|
|
.count();
|
|
assert_eq!(stream_opens, 1);
|
|
|
|
// The edge preamble appears once before object bytes.
|
|
let bytes = written_bytes(&harness, driver::EdgeId(7001));
|
|
assert!(bytes.starts_with(&driver::encode_edge_preamble(driver::EdgeId(7001))));
|
|
let preamble_count = driver::count_preamble_occurrences(&bytes, driver::EdgeId(7001));
|
|
assert_eq!(preamble_count, 1);
|
|
}
|
|
|
|
// This proves receive rendezvous works in both arrival orders and that a
|
|
// pending stream is not read before the receive spec exists.
|
|
#[test]
|
|
fn recv_rendezvous_starts_pump_only_after_spec_and_stream_exist() {
|
|
// Spec first, stream second.
|
|
let mut spec_first = new_driver();
|
|
spec_first.observe(driver::DriverEvent::EstablishRecv(recv_spec()));
|
|
assert!(!spec_first.commands().iter().any(|command| {
|
|
matches!(command, driver::DriverCommand::SpawnRecvPump { .. })
|
|
}));
|
|
spec_first.observe(driver::DriverEvent::IncomingUniStream {
|
|
edge_id: driver::EdgeId(7001),
|
|
stream_id: driver::StreamId(1),
|
|
});
|
|
assert!(spec_first.commands().iter().any(|command| {
|
|
matches!(command, driver::DriverCommand::SpawnRecvPump { edge_id: driver::EdgeId(7001), .. })
|
|
}));
|
|
|
|
// Stream first, spec second.
|
|
let mut stream_first = new_driver();
|
|
stream_first.observe(driver::DriverEvent::IncomingUniStream {
|
|
edge_id: driver::EdgeId(7001),
|
|
stream_id: driver::StreamId(2),
|
|
});
|
|
assert!(!stream_first.stream_reads_started(driver::StreamId(2)));
|
|
stream_first.observe(driver::DriverEvent::EstablishRecv(recv_spec()));
|
|
assert!(stream_first.stream_reads_started(driver::StreamId(2)));
|
|
}
|
|
|
|
// This proves the recv pump is byte-blind after demux, copies QUIC bytes into
|
|
// ingress ring spans, advances commit after copy, emits readable wakes, and
|
|
// stops reading under backpressure.
|
|
#[test]
|
|
fn recv_pump_copies_bytes_without_parsing_and_respects_backpressure() {
|
|
// Rendezvous a receive pump.
|
|
let mut harness = new_driver();
|
|
harness.observe(driver::DriverEvent::IncomingUniStream {
|
|
edge_id: driver::EdgeId(7001),
|
|
stream_id: driver::StreamId(1),
|
|
});
|
|
harness.observe(driver::DriverEvent::EstablishRecv(recv_spec()));
|
|
|
|
// Deliver bytes that happen to look like an object header. The pump must
|
|
// copy them blindly, not parse them.
|
|
harness.observe(driver::DriverEvent::StreamBytesRead {
|
|
edge_id: driver::EdgeId(7001),
|
|
bytes: driver::fake_object_header_bytes(),
|
|
});
|
|
assert!(!harness.events().iter().any(|event| {
|
|
matches!(event, driver::DriverEventOut::ObjectHeaderParsed { .. })
|
|
}));
|
|
assert!(harness.ring_commit(driver::EdgeId(7001)) > 0);
|
|
assert!(harness.wake_hints().iter().any(|wake| {
|
|
matches!(wake, driver::WakeHint::RingReadable { edge_id: driver::EdgeId(7001) })
|
|
}));
|
|
|
|
// With no ring space, the pump stops reading and waits for RingWritable.
|
|
harness.observe(driver::DriverEvent::IngressRingFull {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
assert!(!harness.is_reading_stream(driver::EdgeId(7001)));
|
|
harness.observe(driver::DriverEvent::RingWritable {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
assert!(harness.is_reading_stream(driver::EdgeId(7001)));
|
|
}
|
|
|
|
// This proves the send pump writes committed egress bytes, advances consume
|
|
// only after write_all accepts bytes, emits writable wakes, and keeps ownership
|
|
// of unread bytes while network flow control stalls.
|
|
#[test]
|
|
fn send_pump_advances_consume_only_after_write_acceptance() {
|
|
// Establish a send pump and make bytes readable.
|
|
let mut harness = new_driver();
|
|
harness.observe(driver::DriverEvent::EstablishSend(send_spec()));
|
|
harness.observe(driver::DriverEvent::EgressBytesCommitted {
|
|
edge_id: driver::EdgeId(7001),
|
|
bytes: b"payload".to_vec(),
|
|
});
|
|
harness.observe(driver::DriverEvent::NetworkStalled {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
|
|
// Stalled network keeps ownership of unread ring bytes.
|
|
assert_eq!(harness.ring_consume(driver::EdgeId(7001)), 0);
|
|
|
|
// Once write_all accepts the bytes, consume advances and writable is hinted.
|
|
harness.observe(driver::DriverEvent::WriteAllAccepted {
|
|
edge_id: driver::EdgeId(7001),
|
|
byte_count: 7,
|
|
});
|
|
assert_eq!(harness.ring_consume(driver::EdgeId(7001)), 7);
|
|
assert!(harness.wake_hints().iter().any(|wake| {
|
|
matches!(wake, driver::WakeHint::RingWritable { edge_id: driver::EdgeId(7001) })
|
|
}));
|
|
}
|
|
|
|
// This proves read, write, protocol, and stop outcomes are surfaced as
|
|
// StreamFault or PumpStopped events.
|
|
#[test]
|
|
fn driver_faults_and_stop_emit_stream_fault_or_pump_stopped() {
|
|
// Read error faults the receive edge.
|
|
let mut recv = new_driver();
|
|
recv.observe(driver::DriverEvent::IncomingUniStream {
|
|
edge_id: driver::EdgeId(7001),
|
|
stream_id: driver::StreamId(1),
|
|
});
|
|
recv.observe(driver::DriverEvent::EstablishRecv(recv_spec()));
|
|
recv.observe(driver::DriverEvent::ReadError {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
assert!(recv.events().iter().any(|event| {
|
|
matches!(event, driver::DriverEventOut::StreamFault { edge_id: driver::EdgeId(7001), .. })
|
|
}));
|
|
|
|
// Write error faults the send edge.
|
|
let mut send = new_driver();
|
|
send.observe(driver::DriverEvent::EstablishSend(send_spec()));
|
|
send.observe(driver::DriverEvent::WriteError {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
assert!(send.events().iter().any(|event| {
|
|
matches!(event, driver::DriverEventOut::StreamFault { edge_id: driver::EdgeId(7001), .. })
|
|
}));
|
|
|
|
// StopEdge stops the corresponding pump.
|
|
send.observe(driver::DriverEvent::StopEdge {
|
|
edge_id: driver::EdgeId(7001),
|
|
});
|
|
assert!(send.events().iter().any(|event| {
|
|
matches!(event, driver::DriverEventOut::PumpStopped { edge_id: driver::EdgeId(7001), .. })
|
|
}));
|
|
}
|