From 6f7adc80c5750045dbaf4e0eaf467078c1a7badf Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Wed, 11 Mar 2026 08:32:02 +0100 Subject: [PATCH] test(appd): add unit tests for IPC message codec and session registry ipc.rs tests (4 tests): - request_msgpack_roundtrip: LaunchApp serializes and deserializes with correct field values. - response_msgpack_roundtrip: LaunchAck round-trips through MessagePack. - frame_write_read_roundtrip: write_frame encodes a 4-byte LE length header + body; read_frame decodes the framed request correctly. - read_frame_eof_returns_none: empty stream returns None without error. main.rs tests (5 tests): - registry_launch_increments_id: each launch returns a strictly increasing session ID. - registry_terminate_known_session: terminate returns true and state transitions to NotFound. - registry_terminate_unknown_returns_false: terminate on missing ID returns false. - registry_running_ids_reflects_live_sessions: running_ids returns all active sessions; terminated sessions are removed. - registry_state_not_found_for_unknown: querying an unknown session ID returns AppStateKind::NotFound. Also extends scripts/wsl-test.sh to run weft-appd tests alongside weft-compositor tests. --- crates/weft-appd/src/ipc.rs | 65 ++++++++++++++++++++++++++++++++++++ crates/weft-appd/src/main.rs | 46 +++++++++++++++++++++++++ scripts/wsl-test.sh | 5 +++ 3 files changed, 116 insertions(+) diff --git a/crates/weft-appd/src/ipc.rs b/crates/weft-appd/src/ipc.rs index 1899190..3566a07 100644 --- a/crates/weft-appd/src/ipc.rs +++ b/crates/weft-appd/src/ipc.rs @@ -68,3 +68,68 @@ pub async fn write_frame( writer.write_all(&body).await?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn request_msgpack_roundtrip() { + let req = Request::LaunchApp { + app_id: "com.example.app".into(), + surface_id: 42, + }; + let bytes = rmp_serde::to_vec(&req).unwrap(); + let decoded: Request = rmp_serde::from_slice(&bytes).unwrap(); + match decoded { + Request::LaunchApp { app_id, surface_id } => { + assert_eq!(app_id, "com.example.app"); + assert_eq!(surface_id, 42); + } + _ => panic!("wrong variant"), + } + } + + #[test] + fn response_msgpack_roundtrip() { + let resp = Response::LaunchAck { session_id: 7 }; + let bytes = rmp_serde::to_vec(&resp).unwrap(); + let decoded: Response = rmp_serde::from_slice(&bytes).unwrap(); + match decoded { + Response::LaunchAck { session_id } => assert_eq!(session_id, 7), + _ => panic!("wrong variant"), + } + } + + #[tokio::test] + async fn frame_write_read_roundtrip() { + let resp = Response::RunningApps { + session_ids: vec![1, 2, 3], + }; + let mut buf: Vec = Vec::new(); + write_frame(&mut buf, &resp).await.unwrap(); + + assert_eq!( + buf.len() as u32, + u32::from_le_bytes(buf[..4].try_into().unwrap()) + 4 + ); + + let req_to_write = Request::QueryRunning; + let mut req_buf: Vec = Vec::new(); + let body = rmp_serde::to_vec(&req_to_write).unwrap(); + let len = (body.len() as u32).to_le_bytes(); + req_buf.extend_from_slice(&len); + req_buf.extend_from_slice(&body); + + let mut cursor = std::io::Cursor::new(req_buf); + let decoded = read_frame(&mut cursor).await.unwrap(); + assert!(matches!(decoded, Some(Request::QueryRunning))); + } + + #[tokio::test] + async fn read_frame_eof_returns_none() { + let mut empty = std::io::Cursor::new(Vec::::new()); + let result = read_frame(&mut empty).await.unwrap(); + assert!(result.is_none()); + } +} diff --git a/crates/weft-appd/src/main.rs b/crates/weft-appd/src/main.rs index bc1714e..8650807 100644 --- a/crates/weft-appd/src/main.rs +++ b/crates/weft-appd/src/main.rs @@ -155,3 +155,49 @@ fn appd_socket_path() -> anyhow::Result { Ok(PathBuf::from(runtime_dir).join("weft/appd.sock")) } + +#[cfg(test)] +mod tests { + use super::*; + use ipc::AppStateKind; + + #[test] + fn registry_launch_increments_id() { + let mut reg = SessionRegistry::default(); + let id1 = reg.launch("com.example.a"); + let id2 = reg.launch("com.example.b"); + assert!(id2 > id1); + } + + #[test] + fn registry_terminate_known_session() { + let mut reg = SessionRegistry::default(); + let id = reg.launch("com.example.app"); + assert!(reg.terminate(id)); + assert!(matches!(reg.state(id), AppStateKind::NotFound)); + } + + #[test] + fn registry_terminate_unknown_returns_false() { + let mut reg = SessionRegistry::default(); + assert!(!reg.terminate(999)); + } + + #[test] + fn registry_running_ids_reflects_live_sessions() { + let mut reg = SessionRegistry::default(); + let id1 = reg.launch("a"); + let id2 = reg.launch("b"); + let mut ids = reg.running_ids(); + ids.sort(); + assert_eq!(ids, vec![id1, id2]); + reg.terminate(id1); + assert_eq!(reg.running_ids(), vec![id2]); + } + + #[test] + fn registry_state_not_found_for_unknown() { + let reg = SessionRegistry::default(); + assert!(matches!(reg.state(42), AppStateKind::NotFound)); + } +} diff --git a/scripts/wsl-test.sh b/scripts/wsl-test.sh index d802cfa..67772d4 100644 --- a/scripts/wsl-test.sh +++ b/scripts/wsl-test.sh @@ -25,5 +25,10 @@ cd "$PROJECT" echo "==> cargo test -p weft-compositor" cargo test -p weft-compositor 2>&1 + +echo "" +echo "==> cargo test -p weft-appd" +cargo test -p weft-appd 2>&1 + echo "" echo "ALL DONE"