it: test seat creation and broadcast
This commit is contained in:
parent
fa8d079c72
commit
cdab4d4cad
9 changed files with 121 additions and 27 deletions
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl Object for WlRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(WlRegistry);
|
||||
dedicated_add_obj!(WlRegistry, WlRegistryId, registries);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum WlRegistryError {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
src/it/tests/t0005_create_seat.rs
Normal file
31
src/it/tests/t0005_create_seat.rs
Normal 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(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue