feat(v1): harden typed runtime boundaries
Elect one canonical EffectBatch codec, remove the parallel postcard API, and strengthen fail-closed host, form, sync, WASM, macro, generated-contract, and test-harness proofs with mutation-driven coverage. req: wire/008 req: wire/009 req: wire/010 req: push/008 req: client_local/015 req: client_local/016 req: client_local/017 req: client_local/018 req: client_local/019 req: sync/024 req: sync/025 req: sync/026 req: sync/027 req: sync/028 req: sync/029 req: test/020 req: test/021
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use hemx_test::TestProcess;
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn process_harness_reports_early_exit_with_context() {
|
||||
@@ -27,5 +28,89 @@ fn process_harness_reports_early_exit_with_context() {
|
||||
assert!(message.contains("exited with"), "{message}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_harness_waits_for_readiness_and_reaps_on_drop() {
|
||||
// test req: test/019
|
||||
let reservation = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = reservation.local_addr().unwrap().to_string();
|
||||
drop(reservation);
|
||||
|
||||
let mut command = Command::new(std::env::current_exe().unwrap());
|
||||
command
|
||||
.arg("--exact")
|
||||
.arg("helper_process_listens")
|
||||
.arg("--nocapture")
|
||||
.env("HEMX_TEST_PROCESS_ADDR", &addr);
|
||||
|
||||
let process = TestProcess::start(command, "listening helper", &addr, Duration::from_secs(2))
|
||||
.expect("readiness must observe the helper listener");
|
||||
assert!(TcpStream::connect(&addr).is_ok());
|
||||
drop(process);
|
||||
|
||||
let deadline = Instant::now() + Duration::from_secs(2);
|
||||
while TcpStream::connect(&addr).is_ok() && Instant::now() < deadline {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
assert!(
|
||||
TcpStream::connect(&addr).is_err(),
|
||||
"drop must reap the helper"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_harness_reports_spawn_and_readiness_timeout_errors() {
|
||||
// test req: test/019
|
||||
let spawn_error = match TestProcess::start(
|
||||
Command::new("/definitely/not/a/hemx/executable"),
|
||||
"missing helper",
|
||||
"127.0.0.1:9",
|
||||
Duration::from_millis(10),
|
||||
) {
|
||||
Ok(_) => panic!("spawn failure must be returned, not panic"),
|
||||
Err(error) => error,
|
||||
};
|
||||
assert!(spawn_error
|
||||
.to_string()
|
||||
.contains("failed to spawn missing helper"));
|
||||
|
||||
let reservation = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let unused_addr = reservation.local_addr().unwrap().to_string();
|
||||
drop(reservation);
|
||||
let mut command = Command::new(std::env::current_exe().unwrap());
|
||||
command
|
||||
.arg("--exact")
|
||||
.arg("helper_process_sleeps")
|
||||
.arg("--nocapture")
|
||||
.env("HEMX_TEST_PROCESS_SLEEP", "1");
|
||||
let timeout = match TestProcess::start(
|
||||
command,
|
||||
"non-listening helper",
|
||||
&unused_addr,
|
||||
Duration::from_millis(100),
|
||||
) {
|
||||
Ok(_) => panic!("non-listening process must time out"),
|
||||
Err(error) => error,
|
||||
};
|
||||
let message = timeout.to_string();
|
||||
assert!(message.contains("timed out"), "{message}");
|
||||
assert!(message.contains("non-listening helper"), "{message}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn helper_process_exits_successfully() {}
|
||||
|
||||
#[test]
|
||||
fn helper_process_listens() {
|
||||
let Ok(addr) = std::env::var("HEMX_TEST_PROCESS_ADDR") else {
|
||||
return;
|
||||
};
|
||||
let _listener = TcpListener::bind(addr).expect("bind helper listener");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn helper_process_sleeps() {
|
||||
if std::env::var_os("HEMX_TEST_PROCESS_SLEEP").is_some() {
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user