bin-runner #36
2 changed files with 94 additions and 0 deletions
|
|
@ -10,3 +10,4 @@ wasmtime = "29"
|
|||
[dev-dependencies]
|
||||
swactor = { path = "../..", features = ["getrandom"] }
|
||||
wat = "1"
|
||||
proptest = "1"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use swactor::actor::{ActorAddress, ActorInterface};
|
|||
use swactor::runtime::{Ctx, Runtime, RuntimeConfig};
|
||||
use swactor_wasm_actor::{ByteMessage, SharedEngine, WasmActorBuilder, WasmActorError};
|
||||
|
||||
use proptest::prelude::*;
|
||||
|
||||
fn guest_wasm(name: &str) -> Vec<u8> {
|
||||
let path = format!(
|
||||
"{}/tests/guests/{name}/target/wasm32-unknown-unknown/release/{name}_guest.wasm",
|
||||
|
|
@ -737,3 +739,94 @@ fn native_actor_communicates_with_wasm_actor() {
|
|||
let received = inbox.try_recv().expect("wasm actor should have echoed");
|
||||
assert_eq!(received.0, b"from native");
|
||||
}
|
||||
|
||||
// ── Multi-worker: WASM actors across threads ─────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn wasm_actor_works_on_multi_worker_runtime() {
|
||||
// Spawn a WASM echo actor on a 2-worker runtime and verify message
|
||||
// round-trip works across threads. This is a smoke test for Send safety
|
||||
// of wasmtime Store<HostState>.
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let config = RuntimeConfig {
|
||||
num_threads: 2,
|
||||
..RuntimeConfig::default()
|
||||
};
|
||||
let rt = Runtime::new(config);
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
let payload = b"multi-worker";
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), payload)).unwrap();
|
||||
|
||||
// Use run() to drive the runtime on background threads
|
||||
let handle = rt.run().unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
|
||||
let received = inbox.try_recv().expect("wasm actor should echo on MT runtime");
|
||||
assert_eq!(received.0, payload);
|
||||
|
||||
handle.shutdown();
|
||||
}
|
||||
|
||||
// ── Property-based: arbitrary bytes round-trip through echo ──────────────────
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn prop_echo_roundtrips_arbitrary_bytes(payload in proptest::collection::vec(any::<u8>(), 0..500)) {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
let msg = framed_msg(inbox.addr(), &payload);
|
||||
rt.send_to(addr, msg).unwrap();
|
||||
rt.tick();
|
||||
|
||||
if payload.is_empty() {
|
||||
// Echo guest: if total len < 32, no reply (32B addr + 0B payload = 32, but
|
||||
// the framed message is 32 + 0 = 32 bytes, and echo checks `len < 32`)
|
||||
// Actually: framed_msg produces 32 + payload.len() bytes. When payload
|
||||
// is empty, total is 32, and echo checks `if len < 32 { return; }`.
|
||||
// len == 32 passes the check! So dest_ptr = ptr, payload_ptr = ptr+32,
|
||||
// payload_len = 0 → sends a 0-byte message.
|
||||
// Let's just check: if we got something, it matches.
|
||||
if let Some(received) = inbox.try_recv() {
|
||||
prop_assert_eq!(received.0, payload);
|
||||
}
|
||||
} else {
|
||||
let received = inbox.try_recv().expect("echo should return non-empty payload");
|
||||
prop_assert_eq!(received.0, payload);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prop_double_always_sends_exactly_two_copies(payload in proptest::collection::vec(any::<u8>(), 1..500)) {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, guest_wasm("double"))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
let msg = framed_msg(inbox.addr(), &payload);
|
||||
rt.send_to(addr, msg).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let first = inbox.try_recv().expect("double should send first copy");
|
||||
let second = inbox.try_recv().expect("double should send second copy");
|
||||
prop_assert_eq!(&first.0, &payload);
|
||||
prop_assert_eq!(&second.0, &payload);
|
||||
prop_assert!(inbox.try_recv().is_none(), "exactly two messages expected");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue