test(wasm-actor): cycle 59 — local.tee, 16KB payload, dual runtime, i64 wrap (255 tests)
Added 5 tests: local.tee instruction, 16KB payload round-trip, two independent runtimes with WASM actors, i64-to-i32 wrap instruction, random WAT variations property test. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
parent
384a6a56cb
commit
b13a846b1f
1 changed files with 135 additions and 0 deletions
|
|
@ -8679,3 +8679,138 @@ fn builder_accepts_slice_reference() {
|
||||||
rt.send_to(addr, ByteMessage(vec![])).unwrap();
|
rt.send_to(addr, ByteMessage(vec![])).unwrap();
|
||||||
rt.tick();
|
rt.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Cycle 59 ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Guest that uses local.tee instruction (sets local and leaves value on stack)
|
||||||
|
#[test]
|
||||||
|
fn guest_uses_local_tee() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(global $heap (mut i32) (i32.const 65536))
|
||||||
|
(func (export "alloc") (param $len i32) (result i32)
|
||||||
|
global.get $heap
|
||||||
|
global.get $heap
|
||||||
|
local.get $len
|
||||||
|
i32.add
|
||||||
|
global.set $heap)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
;; Use local.tee: ptr2 = alloc_start, also keep on stack
|
||||||
|
(local $ptr2 i32)
|
||||||
|
global.get $heap
|
||||||
|
local.tee $ptr2
|
||||||
|
drop ;; just exercising the instruction
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
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(b"tee".to_vec())).unwrap();
|
||||||
|
rt.tick(); // no trap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guest that writes a 16KB response — tests larger-than-page payloads round-trip
|
||||||
|
#[test]
|
||||||
|
fn sixteen_kb_payload_round_trip() {
|
||||||
|
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 payload: Vec<u8> = (0..16384u32).map(|i| (i % 251) as u8).collect();
|
||||||
|
rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap();
|
||||||
|
rt.tick();
|
||||||
|
|
||||||
|
let resp = inbox.try_recv().expect("should receive 16KB echo");
|
||||||
|
assert_eq!(resp.0, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two runtimes with WASM actors operating independently at the same time
|
||||||
|
#[test]
|
||||||
|
fn two_independent_runtimes_with_wasm_actors() {
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let actor1 = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap();
|
||||||
|
let actor2 = WasmActorBuilder::new(engine, guest_wasm("double")).build().unwrap();
|
||||||
|
|
||||||
|
let rt1 = Runtime::new(RuntimeConfig::default());
|
||||||
|
let rt2 = Runtime::new(RuntimeConfig::default());
|
||||||
|
|
||||||
|
let inbox1 = rt1.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
let inbox2 = rt2.new_inbox::<ByteMessage>().unwrap();
|
||||||
|
|
||||||
|
let addr1 = rt1.spawn(actor1).unwrap();
|
||||||
|
let addr2 = rt2.spawn(actor2).unwrap();
|
||||||
|
|
||||||
|
rt1.send_to(addr1, framed_msg(inbox1.addr(), b"A")).unwrap();
|
||||||
|
rt2.send_to(addr2, framed_msg(inbox2.addr(), b"B")).unwrap();
|
||||||
|
|
||||||
|
rt1.tick();
|
||||||
|
rt2.tick();
|
||||||
|
|
||||||
|
let msgs1: Vec<_> = std::iter::from_fn(|| inbox1.try_recv().map(|m| m.0)).collect();
|
||||||
|
let msgs2: Vec<_> = std::iter::from_fn(|| inbox2.try_recv().map(|m| m.0)).collect();
|
||||||
|
|
||||||
|
assert_eq!(msgs1.len(), 1, "echo from rt1");
|
||||||
|
assert_eq!(msgs2.len(), 2, "double from rt2");
|
||||||
|
assert_eq!(msgs1[0], b"A");
|
||||||
|
assert!(msgs2.iter().all(|m| m == b"B"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guest that uses i32.wrap_i64 instruction
|
||||||
|
#[test]
|
||||||
|
fn guest_uses_i64_to_i32_wrap() {
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(global $heap (mut i32) (i32.const 65536))
|
||||||
|
(func (export "alloc") (param $len i32) (result i32)
|
||||||
|
global.get $heap
|
||||||
|
global.get $heap
|
||||||
|
local.get $len
|
||||||
|
i32.add
|
||||||
|
global.set $heap)
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
;; Wrap i64 to i32: 0x1_0000_00FF -> 0xFF
|
||||||
|
i64.const 4294967551 ;; 0x1_000000FF
|
||||||
|
i32.wrap_i64
|
||||||
|
;; result is 255, store at ptr
|
||||||
|
local.get $ptr
|
||||||
|
i32.store8 offset=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(b"W".to_vec())).unwrap();
|
||||||
|
rt.tick(); // no trap, wrapping is well-defined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property test: building from random subsets of valid WAT always succeeds or fails cleanly
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn prop_random_valid_wat_variations_never_panic(
|
||||||
|
alloc_offset in 1024u32..60000,
|
||||||
|
pages in 1u32..5,
|
||||||
|
handle_body in proptest::bool::ANY,
|
||||||
|
) {
|
||||||
|
let store_body = if handle_body {
|
||||||
|
"local.get $ptr\nlocal.get $ptr\ni32.load8_u\ni32.store8"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
let wat = format!(r#"(module
|
||||||
|
(memory (export "memory") {pages})
|
||||||
|
(func (export "alloc") (param $len i32) (result i32)
|
||||||
|
i32.const {alloc_offset})
|
||||||
|
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||||
|
{store_body})
|
||||||
|
)"#);
|
||||||
|
let engine = SharedEngine::new().unwrap();
|
||||||
|
let result = WasmActorBuilder::new(engine, wat::parse_str(&wat).unwrap()).build();
|
||||||
|
assert!(result.is_ok(), "valid WAT should build");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue