test: Cycle 34 — From<wasmtime::Error>, 2-thread 3-actor MT, if/else branching
- wasmtime_error_converts_to_wasm_actor_error: From conversion produces Wasmtime variant - three_wasm_actors_on_two_threads: 3 WASM echo actors on 2-thread runtime all deliver - handle_with_if_else_branching: guest uses if/else to send different responses by length All 146 tests pass. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
parent
1dfc210bf0
commit
dfc671fd19
1 changed files with 126 additions and 0 deletions
|
|
@ -5255,3 +5255,129 @@ fn send_payload_at_memory_offset_zero() {
|
|||
let msg = inbox.try_recv().expect("send from offset 0 should work");
|
||||
assert_eq!(msg.0, b"OK");
|
||||
}
|
||||
|
||||
// ── WasmActorError From<wasmtime::Error> conversion ─────────────────────────
|
||||
|
||||
#[test]
|
||||
fn wasmtime_error_converts_to_wasm_actor_error() {
|
||||
// Force a wasmtime::Error through the build path and verify the
|
||||
// From conversion produces WasmActorError::Wasmtime variant.
|
||||
let garbage = vec![0x00, 0x61, 0x73, 0x6D]; // valid magic but truncated
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let result = WasmActorBuilder::new(engine, garbage).build();
|
||||
assert!(result.is_err());
|
||||
match result.err().unwrap() {
|
||||
WasmActorError::Wasmtime(e) => {
|
||||
// wasmtime::Error should have a non-empty message
|
||||
let msg = format!("{e}");
|
||||
assert!(!msg.is_empty(), "wasmtime error should have a message");
|
||||
}
|
||||
other => panic!("expected Wasmtime variant, got {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
// ── 3 WASM actors on 2-thread runtime all deliver ───────────────────────────
|
||||
|
||||
#[test]
|
||||
fn three_wasm_actors_on_two_threads() {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let config = RuntimeConfig {
|
||||
num_threads: 2,
|
||||
..RuntimeConfig::default()
|
||||
};
|
||||
let rt = Runtime::new(config);
|
||||
let counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
// Spawn 3 echo actors
|
||||
let mut addrs = Vec::new();
|
||||
for _ in 0..3 {
|
||||
let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
addrs.push(rt.spawn(actor).unwrap());
|
||||
}
|
||||
|
||||
// Create a native counter actor that counts received messages
|
||||
struct MsgCounter(Arc<AtomicUsize>);
|
||||
impl ActorInterface for MsgCounter {
|
||||
type Incoming = ByteMessage;
|
||||
type Response = ();
|
||||
fn handle(&mut self, _ctx: &Ctx, _msg: ByteMessage) {
|
||||
self.0.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let counter_clone = counter.clone();
|
||||
let counter_addr = rt.spawn(MsgCounter(counter_clone)).unwrap();
|
||||
|
||||
// Send one message to each WASM actor, echoing to the counter
|
||||
for addr in &addrs {
|
||||
rt.send_to(*addr, framed_msg(&counter_addr, b"ping")).unwrap();
|
||||
}
|
||||
|
||||
let handle = rt.run().unwrap();
|
||||
|
||||
// Poll for all 3 messages
|
||||
let mut success = false;
|
||||
for _ in 0..40 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(25));
|
||||
if counter.load(Ordering::SeqCst) >= 3 {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
handle.shutdown();
|
||||
assert!(success, "all 3 WASM actors should deliver on 2-thread runtime");
|
||||
}
|
||||
|
||||
// ── Module with if/else branching in handle ─────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn handle_with_if_else_branching() {
|
||||
// Guest uses if/else to send different payloads based on message length.
|
||||
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)
|
||||
;; If payload (len - 32) > 5, send "BIG", else send "SML"
|
||||
(if (i32.gt_s (i32.sub (local.get $len) (i32.const 32)) (i32.const 5))
|
||||
(then
|
||||
(i32.store8 (i32.const 200) (i32.const 66)) ;; 'B'
|
||||
(i32.store8 (i32.const 201) (i32.const 73)) ;; 'I'
|
||||
(i32.store8 (i32.const 202) (i32.const 71)) ;; 'G'
|
||||
(call $send (local.get $ptr) (i32.const 200) (i32.const 3))
|
||||
)
|
||||
(else
|
||||
(i32.store8 (i32.const 200) (i32.const 83)) ;; 'S'
|
||||
(i32.store8 (i32.const 201) (i32.const 77)) ;; 'M'
|
||||
(i32.store8 (i32.const 202) (i32.const 76)) ;; 'L'
|
||||
(call $send (local.get $ptr) (i32.const 200) (i32.const 3))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
"#;
|
||||
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::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
// Short payload (3 bytes <= 5)
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), b"abc")).unwrap();
|
||||
// Long payload (10 bytes > 5)
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), b"1234567890")).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let msg1 = inbox.try_recv().expect("short message should get response");
|
||||
let msg2 = inbox.try_recv().expect("long message should get response");
|
||||
assert_eq!(msg1.0, b"SML");
|
||||
assert_eq!(msg2.0, b"BIG");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue