test(wasm-actor): cycle 78 — fibonacci recursion, 5-actor inbox, block result (346 tests)
Added 5 tests: fibonacci via recursion, single inbox from five actors, minimal lifecycle no messages, reuse message bytes, block with result value. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
parent
00051f85d8
commit
e96891ae89
1 changed files with 119 additions and 0 deletions
|
|
@ -11259,3 +11259,122 @@ fn actor_replacement_cycle() {
|
||||||
rt.tick();
|
rt.tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Cycle 78 ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Guest with recursive helper that computes fibonacci (bounded)
|
||||||
|
#[test]
|
||||||
|
fn guest_fibonacci_via_recursion() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(func $fib (param $n i32) (result i32)
|
||||||
|
(if (result i32) (i32.le_u (local.get $n) (i32.const 1))
|
||||||
|
(then (local.get $n))
|
||||||
|
(else
|
||||||
|
(i32.add
|
||||||
|
(call $fib (i32.sub (local.get $n) (i32.const 1)))
|
||||||
|
(call $fib (i32.sub (local.get $n) (i32.const 2)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
;; Compute fib(10) = 55, store at ptr
|
||||||
|
(i32.store (local.get $ptr) (call $fib (i32.const 10)))
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
|
||||||
|
.build().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let addr = rt.spawn(actor).unwrap();
|
||||||
|
rt.send_to(addr, ByteMessage(vec![0u8; 4])).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inbox receives messages from multiple WASM actors simultaneously
|
||||||
|
#[test]
|
||||||
|
fn single_inbox_receives_from_five_actors() {
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
|
||||||
|
for i in 0..5u8 {
|
||||||
|
let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap();
|
||||||
|
let addr = rt.spawn(actor).unwrap();
|
||||||
|
rt.send_to(addr, framed_msg(inbox.addr(), &[i])).unwrap();
|
||||||
|
}
|
||||||
|
rt.tick();
|
||||||
|
|
||||||
|
let mut msgs: Vec<Vec<u8>> = std::iter::from_fn(|| inbox.try_recv().map(|m| m.0)).collect();
|
||||||
|
msgs.sort();
|
||||||
|
assert_eq!(msgs.len(), 5);
|
||||||
|
for i in 0..5u8 {
|
||||||
|
assert_eq!(msgs[i as usize], vec![i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guest that does nothing at all — purely exercises spawn+tick+stop lifecycle
|
||||||
|
#[test]
|
||||||
|
fn minimal_lifecycle_no_messages() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(func (export "alloc") (param $len i32) (result i32) i32.const 0)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32))
|
||||||
|
)"#;
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
|
||||||
|
.build().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let addr = rt.spawn(actor).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
rt.tick();
|
||||||
|
rt.stop_actor(addr);
|
||||||
|
rt.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same message bytes reused for multiple sends — no aliasing issues
|
||||||
|
#[test]
|
||||||
|
fn reuse_message_bytes_for_multiple_sends() {
|
||||||
|
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(), b"reuse");
|
||||||
|
for _ in 0..5 {
|
||||||
|
// Clone the same message each time
|
||||||
|
rt.send_to(addr, msg.clone()).unwrap();
|
||||||
|
}
|
||||||
|
rt.tick();
|
||||||
|
|
||||||
|
let msgs: Vec<Vec<u8>> = std::iter::from_fn(|| inbox.try_recv().map(|m| m.0)).collect();
|
||||||
|
assert_eq!(msgs.len(), 5);
|
||||||
|
assert!(msgs.iter().all(|m| m == b"reuse"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guest uses block with result value
|
||||||
|
#[test]
|
||||||
|
fn guest_block_with_result_value() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
;; Block that produces a value
|
||||||
|
(i32.store (local.get $ptr)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.add (local.get $len) (i32.const 42))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
|
||||||
|
.build().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let addr = rt.spawn(actor).unwrap();
|
||||||
|
rt.send_to(addr, ByteMessage(vec![0u8; 4])).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue