bin-runner #36

Merged
zacheryasc merged 103 commits from bin-runner into master 2026-02-13 14:11:40 +00:00
2 changed files with 74 additions and 0 deletions
Showing only changes of commit a171faaad2 - Show all commits

1
Cargo.lock generated
View file

@ -2747,6 +2747,7 @@ dependencies = [
name = "swactor-wasm-actor"
version = "0.1.0"
dependencies = [
"proptest",
"swactor",
"wasmtime",
"wat",

View file

@ -1202,6 +1202,79 @@ fn native_handler_spawns_wasm_actor_and_forwards_message() {
assert_eq!(received.0, b"spawned-echo");
}
// ── Bounded mailbox: WASM actor with backpressure ────────────────────────────
#[test]
fn bounded_mailbox_applies_to_wasm_actor() {
// With a bounded mailbox of capacity 3, sending 10 messages should
// result in only 3 being processed (DropNewest policy).
use swactor::runtime::MailboxOverflow;
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, guest_wasm("echo"))
.build()
.unwrap();
let config = RuntimeConfig {
default_mailbox_capacity: 3,
mailbox_overflow: MailboxOverflow::DropNewest,
..RuntimeConfig::default()
};
let rt = Runtime::new(config);
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
let addr = rt.spawn(actor).unwrap();
// Send 10 messages before any tick — only first 3 should be kept
for i in 0u8..10 {
rt.send_to(addr, framed_msg(inbox.addr(), &[i])).unwrap();
}
rt.tick();
let mut received = Vec::new();
while let Some(msg) = inbox.try_recv() {
received.push(msg.0[0]);
}
assert_eq!(received.len(), 3, "bounded mailbox should limit to 3 messages");
// DropNewest keeps the first 3 sent
assert_eq!(received, vec![0, 1, 2]);
}
// ── Property: alloc failures never kill the actor ────────────────────────────
proptest! {
#[test]
fn prop_any_alloc_return_value_never_kills_actor(alloc_val in -100i32..70000) {
// Regardless of what alloc returns (negative, zero, OOB, valid),
// sending a message should never kill the actor.
let alloc_const = format!("i32.const {alloc_val}");
let wat = format!(r#"
(module
(import "swactor" "send" (func $send (param i32 i32 i32)))
(memory (export "memory") 1)
(func (export "alloc") (param i32) (result i32)
{alloc_const}
)
(func (export "handle") (param i32 i32))
)
"#);
let wasm = wat::parse_str(&wat).unwrap();
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, wasm).build().unwrap();
let rt = Runtime::new(RuntimeConfig::default());
let addr = rt.spawn(actor).unwrap();
// Send a message — should never panic or poison
rt.send_to(addr, ByteMessage(vec![0u8; 100])).unwrap();
rt.tick();
// Actor should still accept messages (not poisoned)
let result = rt.send_to(addr, ByteMessage(vec![1]));
prop_assert!(result.is_ok(), "actor should survive any alloc return value: {alloc_val}");
}
}
// ── Multi-worker: WASM actors across threads ─────────────────────────────────
#[test]