diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index ef4d6cb..9f763ae 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -6806,3 +6806,127 @@ fn double_guest_with_max_byte_value() { assert_eq!(msg2.0, vec![0xFF]); assert!(inbox.try_recv().is_none(), "exactly two copies"); } + +// ── ByteMessage supports large messages (4KB) ─────────────────────────────── + +#[test] +fn large_4kb_message_round_trips() { + 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::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + // 4KB payload (each byte = position mod 256) + let payload: Vec = (0..4096).map(|i| (i & 0xFF) as u8).collect(); + rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0.len(), 4096); + assert_eq!(msg.0, payload); +} + +// ── Guest that sends back payload length as response ──────────────────────── + +#[test] +fn guest_reports_payload_length() { + // Guest reads the payload length (len-32) and sends it back as a 4-byte LE integer. + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Store payload_len = len - 32 as i32 at offset 200 + (i32.store (i32.const 200) (i32.sub (local.get $len) (i32.const 32))) + (call $send (local.get $ptr) (i32.const 200) (i32.const 4)) + ) + ) + "#; + 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 inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + rt.send_to(addr, framed_msg(inbox.addr(), &[0u8; 100])).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + let len = i32::from_le_bytes([msg.0[0], msg.0[1], msg.0[2], msg.0[3]]); + assert_eq!(len, 100, "guest should report payload length of 100"); +} + +// ── Alloc returns 1 (odd alignment) — still works ────────────────────────── + +#[test] +fn alloc_returns_odd_alignment() { + // Guest alloc returns 1 (not aligned). Host should still write correctly. + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 1) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Echo from offset 1 + (call $send + (local.get $ptr) + (i32.add (local.get $ptr) (i32.const 32)) + (i32.sub (local.get $len) (i32.const 32)) + ) + ) + ) + "#; + 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 inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + rt.send_to(addr, framed_msg(inbox.addr(), b"odd-align")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0, b"odd-align"); +} + +// ── SharedEngine clone + Debug ────────────────────────────────────────────── + +#[test] +fn shared_engine_clone_and_debug() { + let engine = SharedEngine::new().unwrap(); + let cloned = engine.clone(); + let debug1 = format!("{:?}", engine); + let debug2 = format!("{:?}", cloned); + assert_eq!(debug1, debug2, "cloned engine should have same debug repr"); +} + +// ── Multiple sequential ticks without messages don't affect WASM actor ────── + +#[test] +fn idle_ticks_dont_affect_wasm_actor() { + 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::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + // 500 idle ticks + for _ in 0..500 { + rt.tick(); + } + + // Should still work + rt.send_to(addr, framed_msg(inbox.addr(), b"after-idle")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0, b"after-idle"); +} \ No newline at end of file