From 56bb9085d3e53f2bd5ebb47af7a8ead92503e32c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 13 Feb 2026 09:22:56 +0000 Subject: [PATCH] =?UTF-8?q?test:=20Cycle=2023=20=E2=80=94=20conditional=20?= =?UTF-8?q?send,=20multi-page=20memory,=20500-message=20sustained=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski --- crates/wasm-actor/tests/wasm_actor.rs | 133 ++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index 5ab1a3a..7f0230d 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -3779,3 +3779,136 @@ fn build_many_actors_from_same_bytes_sequentially() { rt.tick(); } } + +// ── Guest that only sends on even-numbered messages ───────────────────────── + +#[test] +fn guest_conditional_send_based_on_message_content() { + // Guest only sends a reply if the first byte of payload (after the 32-byte + // address) is even. Tests that the outbox is correctly empty when the guest + // decides not to send. + 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 256) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Check if byte at ptr+32 (first payload byte) is even + local.get $ptr + i32.const 32 + i32.add + i32.load8_u + i32.const 2 + i32.rem_u + i32.const 0 + i32.eq + if + ;; Even: send reply + local.get $ptr + local.get $ptr + i32.const 32 + i32.add + local.get $len + i32.const 32 + i32.sub + call $send + end + ;; Odd: do nothing (empty outbox) + ) + ) + "#; + 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(); + + // Send even byte (0) — should get reply + rt.send_to(addr, framed_msg(inbox.addr(), &[0])).unwrap(); + rt.tick(); + assert!(inbox.try_recv().is_some(), "even byte should trigger reply"); + + // Send odd byte (1) — no reply + rt.send_to(addr, framed_msg(inbox.addr(), &[1])).unwrap(); + rt.tick(); + assert!(inbox.try_recv().is_none(), "odd byte should not trigger reply"); + + // Send even byte (2) — should get reply + rt.send_to(addr, framed_msg(inbox.addr(), &[2])).unwrap(); + rt.tick(); + assert!(inbox.try_recv().is_some(), "even byte should trigger reply"); +} + +// ── Guest with multiple memory pages ──────────────────────────────────────── + +#[test] +fn guest_with_multiple_initial_pages_works() { + // Module starts with 4 pages (256KiB). Alloc returns pointer in page 3. + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 4) ;; 4 pages = 262144 bytes + (func (export "alloc") (param i32) (result i32) + i32.const 196608 ;; page 3 start (3 * 65536) + ) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Echo from page 3 + local.get $ptr + local.get $ptr + i32.const 32 + i32.add + local.get $len + i32.const 32 + i32.sub + call $send + ) + ) + "#; + 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(); + + let payload = b"multi-page"; + rt.send_to(addr, framed_msg(inbox.addr(), payload)).unwrap(); + rt.tick(); + + let received = inbox.try_recv().expect("multi-page alloc should work"); + assert_eq!(received.0, payload); +} + +// ── Long-running: echo actor processes 500 messages sequentially ──────────── + +#[test] +fn echo_processes_500_sequential_messages() { + // Sustained message processing without crashes, allocator exhaustion + // handling, and verified actor survival throughout. + 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(); + + let mut received_count = 0; + for i in 0u16..500 { + let payload = i.to_le_bytes(); + rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap(); + rt.tick(); + if let Some(msg) = inbox.try_recv() { + assert_eq!(msg.0, payload, "payload integrity at message {i}"); + received_count += 1; + } + } + + // With 65536-byte allocator and ~40 bytes per alloc (34 + alignment), + // all 500 messages should fit. Verify all echoed correctly. + assert_eq!(received_count, 500, "all 500 messages should echo"); +}