use std::sync::Arc;
use std::time::{Duration, Instant};
use tensor_wasm_core::types::TenantId;
use tensor_wasm_exec::engine::{EngineConfig, TensorWasmEngine};
use tensor_wasm_exec::executor::{SpawnConfig, TensorWasmExecutor};
fn infinite_loop_wasm() -> Vec<u8> {
wat::parse_str(
r#"
(module
(func (export "spin") (loop (br 0)))
)
"#,
)
.unwrap()
}
#[cfg_attr(
windows,
ignore = "wasmtime fiber unwinding on Windows panics on epoch interrupt"
)]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn infinite_loop_terminates_within_2x_deadline() {
let cfg = EngineConfig {
epoch_tick: Duration::from_millis(5),
..EngineConfig::default()
};
let mut engine = TensorWasmEngine::with_config(cfg).expect("engine");
engine.spawn_epoch_ticker();
let engine = Arc::new(engine);
let exec = TensorWasmExecutor::new(engine);
let deadline = Duration::from_millis(100);
let id = exec
.spawn_instance(
SpawnConfig::for_tenant(TenantId(1)).with_deadline(deadline),
&infinite_loop_wasm(),
)
.await
.expect("spawn");
let start = Instant::now();
let res = exec.call_export_with_args(id, "spin", &[]).await;
let elapsed = start.elapsed();
assert!(res.is_err(), "expected the infinite loop to be interrupted");
let twice = deadline * 2;
let limit = twice + Duration::from_millis(100);
assert!(
elapsed <= limit,
"epoch interruption took {:?}, expected ≤ {:?} (2× deadline + slack)",
elapsed,
limit
);
exec.terminate(id).await.expect("terminate");
}