From cdab4d4cad6c63887b1add26329259657221324e Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 3 May 2022 15:25:48 +0200 Subject: [PATCH] it: test seat creation and broadcast --- src/client/objects.rs | 2 +- src/ifs/wl_registry.rs | 2 +- src/it/test_config.rs | 39 +++++++++++++++++++++++++--- src/it/test_ifs/test_registry.rs | 43 +++++++++++++++++++------------ src/it/test_logger.rs | 17 +++++++----- src/it/test_transport.rs | 1 + src/it/testrun.rs | 11 ++++++++ src/it/tests.rs | 2 ++ src/it/tests/t0005_create_seat.rs | 31 ++++++++++++++++++++++ 9 files changed, 121 insertions(+), 27 deletions(-) create mode 100644 src/it/tests/t0005_create_seat.rs diff --git a/src/client/objects.rs b/src/client/objects.rs index ef32eac9..a0bbf436 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -37,7 +37,7 @@ use { pub struct Objects { pub display: CloneCell>>, registry: CopyHashMap>, - registries: CopyHashMap>, + pub registries: CopyHashMap>, pub outputs: CopyHashMap>, pub surfaces: CopyHashMap>, pub xdg_surfaces: CopyHashMap>, diff --git a/src/ifs/wl_registry.rs b/src/ifs/wl_registry.rs index 116f4027..dcc72ae7 100644 --- a/src/ifs/wl_registry.rs +++ b/src/ifs/wl_registry.rs @@ -81,7 +81,7 @@ impl Object for WlRegistry { } } -simple_add_obj!(WlRegistry); +dedicated_add_obj!(WlRegistry, WlRegistryId, registries); #[derive(Debug, Error)] pub enum WlRegistryError { diff --git a/src/it/test_config.rs b/src/it/test_config.rs index b9b96f22..1c879fe5 100644 --- a/src/it/test_config.rs +++ b/src/it/test_config.rs @@ -1,9 +1,9 @@ use { - crate::it::test_error::TestError, + crate::{ifs::wl_seat::SeatId, it::test_error::TestError, utils::stack::Stack}, isnt::std_1::primitive::IsntConstPtrExt, jay_config::_private::{ bincode_ops, - ipc::{ClientMessage, ServerMessage}, + ipc::{ClientMessage, Response, ServerMessage}, ConfigEntry, VERSION, }, std::{cell::Cell, ops::Deref, ptr, rc::Rc}, @@ -26,6 +26,7 @@ where unsafe { let tc = Rc::new(TestConfig { srv: Cell::new(None), + responses: Default::default(), }); let old = CONFIG; CONFIG = tc.deref(); @@ -73,7 +74,9 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) { }; match msg { ServerMessage::Configure { .. } => {} - ServerMessage::Response { .. } => {} + ServerMessage::Response { response } => { + tc.responses.push(response); + } ServerMessage::InvokeShortcut { .. } => {} ServerMessage::NewInputDevice { .. } => {} ServerMessage::DelInputDevice { .. } => {} @@ -96,10 +99,26 @@ struct ServerData { pub struct TestConfig { srv: Cell>, + responses: Stack, +} + +macro_rules! get_response { + ($res:expr, $ty:ident { $($field:ident),+ }) => { + let ($($field,)+) = match $res { + Response::$ty { $($field,)+ } => ($($field,)+), + _ => { + bail!("Server did not send a response to a {} request", stringify!($ty)); + } + }; + } } impl TestConfig { fn send(&self, msg: ClientMessage) -> Result<(), TestError> { + self.send_(&msg) + } + + fn send_(&self, msg: &ClientMessage) -> Result<(), TestError> { let srv = match self.srv.get() { Some(srv) => srv, _ => bail!("srv not set"), @@ -112,10 +131,24 @@ impl TestConfig { Ok(()) } + fn send_with_reply(&self, msg: ClientMessage) -> Result { + self.send_(&msg)?; + match self.responses.pop() { + Some(r) => Ok(r), + _ => bail!("Compositor did not send a response to {:?}", msg), + } + } + pub fn quit(&self) -> Result<(), TestError> { self.send(ClientMessage::Quit) } + pub fn get_seat(&self, name: &str) -> Result { + let reply = self.send_with_reply(ClientMessage::GetSeat { name })?; + get_response!(reply, GetSeat { seat }); + Ok(SeatId::from_raw(seat.0 as _)) + } + fn clear(&self) { unsafe { if let Some(srv) = self.srv.take() { diff --git a/src/it/test_ifs/test_registry.rs b/src/it/test_ifs/test_registry.rs index 6139916f..dd13cf2f 100644 --- a/src/it/test_ifs/test_registry.rs +++ b/src/it/test_ifs/test_registry.rs @@ -1,5 +1,7 @@ use { crate::{ + globals::GlobalName, + ifs::wl_seat::WlSeatGlobal, it::{ test_error::TestError, test_ifs::{ @@ -11,7 +13,7 @@ use { testrun::ParseFull, }, utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap}, - wire::{wl_registry::*, WlRegistryId}, + wire::{wl_registry::*, WlRegistryId, WlSeat}, }, std::{cell::Cell, rc::Rc}, }; @@ -38,6 +40,7 @@ pub struct TestRegistry { pub compositor: CloneCell>>, pub shm: CloneCell>>, pub xdg: CloneCell>>, + pub seats: CopyHashMap>, } macro_rules! singleton { @@ -163,30 +166,38 @@ impl TestRegistry { fn handle_global(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { let ev = Global::parse_full(parser)?; - let prev = self.globals.set( - ev.name, - Rc::new(TestGlobal { - name: ev.name, - interface: ev.interface.to_string(), - version: ev.version, - }), - ); + let global = Rc::new(TestGlobal { + name: ev.name, + interface: ev.interface.to_string(), + version: ev.version, + }); + let prev = self.globals.set(ev.name, global.clone()); + let name = GlobalName::from_raw(ev.name); + if ev.interface == WlSeat.name() { + let seat = match self.tran.run.state.globals.seats.get(&name) { + Some(s) => s, + _ => bail!("Compositor sent seat global but seat does not exist"), + }; + self.seats.set(GlobalName::from_raw(ev.name), seat); + } if prev.is_some() { - self.tran.error(&format!( - "Compositor sent global {} multiple times", - ev.name - )); + bail!("Compositor sent global {} multiple times", ev.name); } Ok(()) } fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { let ev = GlobalRemove::parse_full(parser)?; - if self.globals.remove(&ev.name).is_none() { - self.tran.error(&format!( + let global = match self.globals.remove(&ev.name) { + Some(g) => g, + _ => bail!( "Compositor sent global_remove for {} which does not exist", ev.name - )); + ), + }; + let name = GlobalName::from_raw(ev.name); + if global.interface == WlSeat.name() { + self.seats.remove(&name); } Ok(()) } diff --git a/src/it/test_logger.rs b/src/it/test_logger.rs index 669ed8c3..d07ef06e 100644 --- a/src/it/test_logger.rs +++ b/src/it/test_logger.rs @@ -1,12 +1,17 @@ use { crate::utils::clonecell::CloneCell, log::{Level, LevelFilter, Log, Metadata, Record}, - std::{cell::Cell, fmt::Write as FmtWrite, io::Write, rc::Rc, time::SystemTime}, + std::{ + fmt::Write as FmtWrite, + io::Write, + rc::Rc, + sync::atomic::{AtomicUsize, Ordering}, + time::SystemTime, + }, uapi::{Fd, OwnedFd}, }; -#[thread_local] -static LEVEL: Cell = Cell::new(Level::Info); +static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize); #[thread_local] static FILE: CloneCell>> = CloneCell::new(None); @@ -17,7 +22,7 @@ pub fn install() { } pub fn set_level(level: Level) { - LEVEL.set(level); + LEVEL.store(level as usize, Ordering::Relaxed); log::set_max_level(level.to_level_filter()); } @@ -33,11 +38,11 @@ struct Logger; impl Log for Logger { fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= LEVEL.get() + metadata.level() as usize <= LEVEL.load(Ordering::Relaxed) } fn log(&self, record: &Record) { - if record.level() > LEVEL.get() { + if record.level() as usize > LEVEL.load(Ordering::Relaxed) { return; } let mut buf = String::new(); diff --git a/src/it/test_transport.rs b/src/it/test_transport.rs index 6dbc1334..1aa0a58a 100644 --- a/src/it/test_transport.rs +++ b/src/it/test_transport.rs @@ -54,6 +54,7 @@ impl TestTransport { compositor: Default::default(), shm: Default::default(), xdg: Default::default(), + seats: Default::default(), }); self.send(wl_display::GetRegistry { self_id: WL_DISPLAY_ID, diff --git a/src/it/testrun.rs b/src/it/testrun.rs index d4d72469..a9db48ea 100644 --- a/src/it/testrun.rs +++ b/src/it/testrun.rs @@ -1,6 +1,7 @@ use { crate::{ client::{ClientId, RequestParser}, + ifs::wl_seat::WlSeatGlobal, it::{ test_backend::TestBackend, test_client::TestClient, @@ -89,6 +90,16 @@ impl TestRun { registry, })) } + + pub fn get_seat(&self, name: &str) -> Result, TestError> { + let id = self.cfg.get_seat(name)?; + for seat in self.state.globals.seats.lock().values() { + if seat.id() == id { + return Ok(seat.clone()); + } + } + bail!("Seat {} does not exist", id) + } } pub trait ParseFull<'a>: Sized { diff --git a/src/it/tests.rs b/src/it/tests.rs index 8252a8a4..d8b39b29 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -57,6 +57,7 @@ mod t0001_shm_formats; mod t0002_window; mod t0003_multi_window; mod t0004_quit; +mod t0005_create_seat; pub trait TestCase: Sync { fn name(&self) -> &'static str; @@ -78,5 +79,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> { t0002_window, t0003_multi_window, t0004_quit, + t0005_create_seat, } } diff --git a/src/it/tests/t0005_create_seat.rs b/src/it/tests/t0005_create_seat.rs new file mode 100644 index 00000000..90d1e23b --- /dev/null +++ b/src/it/tests/t0005_create_seat.rs @@ -0,0 +1,31 @@ +use { + crate::{ + globals::GlobalBase, + it::{test_error::TestError, testrun::TestRun}, + }, + std::rc::Rc, +}; + +testcase!(); + +/// Test seat creation and broadcast +async fn test(run: Rc) -> Result<(), TestError> { + let client = run.create_client().await?; + + tassert!(client.registry.seats.is_empty()); + + let seat = run.get_seat("default")?; + + client.sync().await; + + tassert_eq!(client.registry.seats.len(), 1); + + let client_seat = client.registry.seats.get(&seat.name()); + tassert!(client_seat.is_some()); + + let client_seat = client_seat.unwrap(); + + tassert_eq!(seat.id(), client_seat.id()); + + Ok(()) +}