test(wasm-actor): cycle 77 — reverse+echo, shared budget, f64, replacement cycle (341 tests)
Added 4 tests: guest reverses payload then echoes, actors share budget setting, f64 arithmetic, 5-round actor replacement cycle. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
parent
4e743479ee
commit
00051f85d8
1 changed files with 123 additions and 0 deletions
|
|
@ -11135,4 +11135,127 @@ fn guest_early_return_from_handle() {
|
||||||
rt.tick();
|
rt.tick();
|
||||||
let resp = inbox.try_recv().expect("long message should echo");
|
let resp = inbox.try_recv().expect("long message should echo");
|
||||||
assert_eq!(resp.0, b"long-enough");
|
assert_eq!(resp.0, b"long-enough");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Cycle 77 ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Guest that responds with byte at each index: response[0] = payload[len-1], etc.
|
||||||
|
// (reverse payload using a loop, then send)
|
||||||
|
#[test]
|
||||||
|
fn guest_reverses_and_echoes_payload() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(import "swactor" "send" (func $send (param i32 i32 i32)))
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(global $heap (mut i32) (i32.const 2048))
|
||||||
|
(func (export "alloc") (param $len i32) (result i32)
|
||||||
|
(local $ptr i32)
|
||||||
|
(local.set $ptr (global.get $heap))
|
||||||
|
(global.set $heap (i32.add (global.get $heap) (local.get $len)))
|
||||||
|
(local.get $ptr)
|
||||||
|
)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
(local $i i32)
|
||||||
|
(local $payload_start i32)
|
||||||
|
(local $payload_len i32)
|
||||||
|
(local $out_ptr i32)
|
||||||
|
;; Need >= 33 bytes
|
||||||
|
(if (i32.lt_u (local.get $len) (i32.const 33)) (then return))
|
||||||
|
(local.set $payload_start (i32.add (local.get $ptr) (i32.const 32)))
|
||||||
|
(local.set $payload_len (i32.sub (local.get $len) (i32.const 32)))
|
||||||
|
;; Allocate output buffer at offset 900
|
||||||
|
(local.set $out_ptr (i32.const 900))
|
||||||
|
;; Reverse loop
|
||||||
|
(local.set $i (i32.const 0))
|
||||||
|
(block $exit
|
||||||
|
(loop $loop
|
||||||
|
(br_if $exit (i32.ge_u (local.get $i) (local.get $payload_len)))
|
||||||
|
(i32.store8
|
||||||
|
(i32.add (local.get $out_ptr) (local.get $i))
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add (local.get $payload_start)
|
||||||
|
(i32.sub (i32.sub (local.get $payload_len) (i32.const 1)) (local.get $i)))))
|
||||||
|
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
||||||
|
(br $loop)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(call $send (local.get $ptr) (local.get $out_ptr) (local.get $payload_len))
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
|
||||||
|
.build().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
let addr = rt.spawn(actor).unwrap();
|
||||||
|
|
||||||
|
rt.send_to(addr, framed_msg(inbox.addr(), b"abcde")).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
|
||||||
|
let resp = inbox.try_recv().expect("reversed echo");
|
||||||
|
assert_eq!(resp.0, b"edcba");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple actors with different budgets in same runtime
|
||||||
|
#[test]
|
||||||
|
fn actors_share_single_budget_setting() {
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let e1 = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap();
|
||||||
|
let e2 = WasmActorBuilder::new(engine, guest_wasm("echo")).build().unwrap();
|
||||||
|
let mut cfg = RuntimeConfig::default();
|
||||||
|
cfg.actor_message_budget = 3;
|
||||||
|
let rt = Runtime::new(cfg);
|
||||||
|
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
let a1 = rt.spawn(e1).unwrap();
|
||||||
|
let a2 = rt.spawn(e2).unwrap();
|
||||||
|
|
||||||
|
// Send 5 to each
|
||||||
|
for i in 0u8..5 {
|
||||||
|
rt.send_to(a1, framed_msg(inbox.addr(), &[i])).unwrap();
|
||||||
|
rt.send_to(a2, framed_msg(inbox.addr(), &[i + 100])).unwrap();
|
||||||
|
}
|
||||||
|
rt.tick();
|
||||||
|
|
||||||
|
// With budget=3, each actor processes at most 3 per tick
|
||||||
|
let count = std::iter::from_fn(|| inbox.try_recv()).count();
|
||||||
|
assert!(count <= 6, "at most 3 per actor × 2 actors = 6, got {count}");
|
||||||
|
assert!(count >= 2, "at least 1 per actor");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guest uses f64 arithmetic
|
||||||
|
#[test]
|
||||||
|
fn guest_f64_arithmetic() {
|
||||||
|
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)
|
||||||
|
(f64.store (local.get $ptr)
|
||||||
|
(f64.mul (f64.const 2.5) (f64.const 4.0)))
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
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; 8])).unwrap();
|
||||||
|
rt.tick(); // stores 10.0 as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn, send, stop, respawn with new actor — complete replacement
|
||||||
|
#[test]
|
||||||
|
fn actor_replacement_cycle() {
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let rt = Runtime::new(RuntimeConfig::default());
|
||||||
|
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
|
||||||
|
for round 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(), &[round])).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
let resp = inbox.try_recv().expect("each round should echo");
|
||||||
|
assert_eq!(resp.0, vec![round]);
|
||||||
|
rt.stop_actor(addr);
|
||||||
|
rt.tick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue