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.
This commit is contained in:
Marco Allegretti 2026-03-11 08:32:02 +01:00
parent 538eccd4c6
commit 6f7adc80c5
3 changed files with 116 additions and 0 deletions

View file

@ -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<u8> = 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<u8> = 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::<u8>::new());
let result = read_frame(&mut empty).await.unwrap();
assert!(result.is_none());
}
}

View file

@ -155,3 +155,49 @@ fn appd_socket_path() -> anyhow::Result<PathBuf> {
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));
}
}

View file

@ -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"