1
0
Fork 0
forked from wry/wry

it: test seat creation and broadcast

This commit is contained in:
Julian Orth 2022-05-03 15:25:48 +02:00
parent fa8d079c72
commit cdab4d4cad
9 changed files with 121 additions and 27 deletions

View file

@ -37,7 +37,7 @@ use {
pub struct Objects {
pub display: CloneCell<Option<Rc<WlDisplay>>>,
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
registries: CopyHashMap<WlRegistryId, Rc<WlRegistry>>,
pub registries: CopyHashMap<WlRegistryId, Rc<WlRegistry>>,
pub outputs: CopyHashMap<WlOutputId, Rc<WlOutput>>,
pub surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
pub xdg_surfaces: CopyHashMap<XdgSurfaceId, Rc<XdgSurface>>,

View file

@ -81,7 +81,7 @@ impl Object for WlRegistry {
}
}
simple_add_obj!(WlRegistry);
dedicated_add_obj!(WlRegistry, WlRegistryId, registries);
#[derive(Debug, Error)]
pub enum WlRegistryError {

View file

@ -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<Option<ServerData>>,
responses: Stack<Response>,
}
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<Response, TestError> {
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<SeatId, TestError> {
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() {

View file

@ -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<Option<Rc<TestCompositor>>>,
pub shm: CloneCell<Option<Rc<TestShm>>>,
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
}
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(())
}

View file

@ -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<Level> = Cell::new(Level::Info);
static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);
#[thread_local]
static FILE: CloneCell<Option<Rc<OwnedFd>>> = 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();

View file

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

View file

@ -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<Rc<WlSeatGlobal>, 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 {

View file

@ -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,
}
}

View file

@ -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<TestRun>) -> 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(())
}