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 struct Objects {
|
||||||
pub display: CloneCell<Option<Rc<WlDisplay>>>,
|
pub display: CloneCell<Option<Rc<WlDisplay>>>,
|
||||||
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
|
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
|
||||||
registries: CopyHashMap<WlRegistryId, Rc<WlRegistry>>,
|
pub registries: CopyHashMap<WlRegistryId, Rc<WlRegistry>>,
|
||||||
pub outputs: CopyHashMap<WlOutputId, Rc<WlOutput>>,
|
pub outputs: CopyHashMap<WlOutputId, Rc<WlOutput>>,
|
||||||
pub surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
|
pub surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
|
||||||
pub xdg_surfaces: CopyHashMap<XdgSurfaceId, Rc<XdgSurface>>,
|
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)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlRegistryError {
|
pub enum WlRegistryError {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::it::test_error::TestError,
|
crate::{ifs::wl_seat::SeatId, it::test_error::TestError, utils::stack::Stack},
|
||||||
isnt::std_1::primitive::IsntConstPtrExt,
|
isnt::std_1::primitive::IsntConstPtrExt,
|
||||||
jay_config::_private::{
|
jay_config::_private::{
|
||||||
bincode_ops,
|
bincode_ops,
|
||||||
ipc::{ClientMessage, ServerMessage},
|
ipc::{ClientMessage, Response, ServerMessage},
|
||||||
ConfigEntry, VERSION,
|
ConfigEntry, VERSION,
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
||||||
|
|
@ -26,6 +26,7 @@ where
|
||||||
unsafe {
|
unsafe {
|
||||||
let tc = Rc::new(TestConfig {
|
let tc = Rc::new(TestConfig {
|
||||||
srv: Cell::new(None),
|
srv: Cell::new(None),
|
||||||
|
responses: Default::default(),
|
||||||
});
|
});
|
||||||
let old = CONFIG;
|
let old = CONFIG;
|
||||||
CONFIG = tc.deref();
|
CONFIG = tc.deref();
|
||||||
|
|
@ -73,7 +74,9 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||||
};
|
};
|
||||||
match msg {
|
match msg {
|
||||||
ServerMessage::Configure { .. } => {}
|
ServerMessage::Configure { .. } => {}
|
||||||
ServerMessage::Response { .. } => {}
|
ServerMessage::Response { response } => {
|
||||||
|
tc.responses.push(response);
|
||||||
|
}
|
||||||
ServerMessage::InvokeShortcut { .. } => {}
|
ServerMessage::InvokeShortcut { .. } => {}
|
||||||
ServerMessage::NewInputDevice { .. } => {}
|
ServerMessage::NewInputDevice { .. } => {}
|
||||||
ServerMessage::DelInputDevice { .. } => {}
|
ServerMessage::DelInputDevice { .. } => {}
|
||||||
|
|
@ -96,10 +99,26 @@ struct ServerData {
|
||||||
|
|
||||||
pub struct TestConfig {
|
pub struct TestConfig {
|
||||||
srv: Cell<Option<ServerData>>,
|
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 {
|
impl TestConfig {
|
||||||
fn send(&self, msg: ClientMessage) -> Result<(), TestError> {
|
fn send(&self, msg: ClientMessage) -> Result<(), TestError> {
|
||||||
|
self.send_(&msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_(&self, msg: &ClientMessage) -> Result<(), TestError> {
|
||||||
let srv = match self.srv.get() {
|
let srv = match self.srv.get() {
|
||||||
Some(srv) => srv,
|
Some(srv) => srv,
|
||||||
_ => bail!("srv not set"),
|
_ => bail!("srv not set"),
|
||||||
|
|
@ -112,10 +131,24 @@ impl TestConfig {
|
||||||
Ok(())
|
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> {
|
pub fn quit(&self) -> Result<(), TestError> {
|
||||||
self.send(ClientMessage::Quit)
|
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) {
|
fn clear(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(srv) = self.srv.take() {
|
if let Some(srv) = self.srv.take() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError,
|
test_error::TestError,
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
|
|
@ -11,7 +13,7 @@ use {
|
||||||
testrun::ParseFull,
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||||
wire::{wl_registry::*, WlRegistryId},
|
wire::{wl_registry::*, WlRegistryId, WlSeat},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -38,6 +40,7 @@ pub struct TestRegistry {
|
||||||
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
||||||
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
||||||
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
||||||
|
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
|
|
@ -163,30 +166,38 @@ impl TestRegistry {
|
||||||
|
|
||||||
fn handle_global(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_global(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = Global::parse_full(parser)?;
|
let ev = Global::parse_full(parser)?;
|
||||||
let prev = self.globals.set(
|
let global = Rc::new(TestGlobal {
|
||||||
ev.name,
|
name: ev.name,
|
||||||
Rc::new(TestGlobal {
|
interface: ev.interface.to_string(),
|
||||||
name: ev.name,
|
version: ev.version,
|
||||||
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() {
|
if prev.is_some() {
|
||||||
self.tran.error(&format!(
|
bail!("Compositor sent global {} multiple times", ev.name);
|
||||||
"Compositor sent global {} multiple times",
|
|
||||||
ev.name
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = GlobalRemove::parse_full(parser)?;
|
let ev = GlobalRemove::parse_full(parser)?;
|
||||||
if self.globals.remove(&ev.name).is_none() {
|
let global = match self.globals.remove(&ev.name) {
|
||||||
self.tran.error(&format!(
|
Some(g) => g,
|
||||||
|
_ => bail!(
|
||||||
"Compositor sent global_remove for {} which does not exist",
|
"Compositor sent global_remove for {} which does not exist",
|
||||||
ev.name
|
ev.name
|
||||||
));
|
),
|
||||||
|
};
|
||||||
|
let name = GlobalName::from_raw(ev.name);
|
||||||
|
if global.interface == WlSeat.name() {
|
||||||
|
self.seats.remove(&name);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
use {
|
use {
|
||||||
crate::utils::clonecell::CloneCell,
|
crate::utils::clonecell::CloneCell,
|
||||||
log::{Level, LevelFilter, Log, Metadata, Record},
|
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},
|
uapi::{Fd, OwnedFd},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[thread_local]
|
static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);
|
||||||
static LEVEL: Cell<Level> = Cell::new(Level::Info);
|
|
||||||
|
|
||||||
#[thread_local]
|
#[thread_local]
|
||||||
static FILE: CloneCell<Option<Rc<OwnedFd>>> = CloneCell::new(None);
|
static FILE: CloneCell<Option<Rc<OwnedFd>>> = CloneCell::new(None);
|
||||||
|
|
@ -17,7 +22,7 @@ pub fn install() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_level(level: Level) {
|
pub fn set_level(level: Level) {
|
||||||
LEVEL.set(level);
|
LEVEL.store(level as usize, Ordering::Relaxed);
|
||||||
log::set_max_level(level.to_level_filter());
|
log::set_max_level(level.to_level_filter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,11 +38,11 @@ struct Logger;
|
||||||
|
|
||||||
impl Log for Logger {
|
impl Log for Logger {
|
||||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||||
metadata.level() <= LEVEL.get()
|
metadata.level() as usize <= LEVEL.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &Record) {
|
fn log(&self, record: &Record) {
|
||||||
if record.level() > LEVEL.get() {
|
if record.level() as usize > LEVEL.load(Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ impl TestTransport {
|
||||||
compositor: Default::default(),
|
compositor: Default::default(),
|
||||||
shm: Default::default(),
|
shm: Default::default(),
|
||||||
xdg: Default::default(),
|
xdg: Default::default(),
|
||||||
|
seats: Default::default(),
|
||||||
});
|
});
|
||||||
self.send(wl_display::GetRegistry {
|
self.send(wl_display::GetRegistry {
|
||||||
self_id: WL_DISPLAY_ID,
|
self_id: WL_DISPLAY_ID,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{ClientId, RequestParser},
|
client::{ClientId, RequestParser},
|
||||||
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
it::{
|
it::{
|
||||||
test_backend::TestBackend,
|
test_backend::TestBackend,
|
||||||
test_client::TestClient,
|
test_client::TestClient,
|
||||||
|
|
@ -89,6 +90,16 @@ impl TestRun {
|
||||||
registry,
|
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 {
|
pub trait ParseFull<'a>: Sized {
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ mod t0001_shm_formats;
|
||||||
mod t0002_window;
|
mod t0002_window;
|
||||||
mod t0003_multi_window;
|
mod t0003_multi_window;
|
||||||
mod t0004_quit;
|
mod t0004_quit;
|
||||||
|
mod t0005_create_seat;
|
||||||
|
|
||||||
pub trait TestCase: Sync {
|
pub trait TestCase: Sync {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
@ -78,5 +79,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||||
t0002_window,
|
t0002_window,
|
||||||
t0003_multi_window,
|
t0003_multi_window,
|
||||||
t0004_quit,
|
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