config: add TestConfig
This commit is contained in:
parent
f92c9c6027
commit
e212e0b8b1
7 changed files with 175 additions and 6 deletions
|
|
@ -238,7 +238,7 @@ async fn start_compositor3(state: Rc<State>, test_future: Option<TestFuture>) {
|
||||||
fn load_config(state: &Rc<State>, #[allow(unused_variables)] for_test: bool) -> ConfigProxy {
|
fn load_config(state: &Rc<State>, #[allow(unused_variables)] for_test: bool) -> ConfigProxy {
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
if for_test {
|
if for_test {
|
||||||
// todo
|
return ConfigProxy::for_test(state);
|
||||||
}
|
}
|
||||||
match ConfigProxy::from_config_dir(state) {
|
match ConfigProxy::from_config_dir(state) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use {
|
||||||
backend::{ConnectorId, InputDeviceId},
|
backend::{ConnectorId, InputDeviceId},
|
||||||
config::handler::ConfigProxyHandler,
|
config::handler::ConfigProxyHandler,
|
||||||
ifs::wl_seat::SeatId,
|
ifs::wl_seat::SeatId,
|
||||||
|
it::test_config::TEST_CONFIG_ENTRY,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, numcell::NumCell, oserror::OsError, ptr_ext::PtrExt,
|
clonecell::CloneCell, numcell::NumCell, oserror::OsError, ptr_ext::PtrExt,
|
||||||
|
|
@ -180,6 +181,11 @@ impl ConfigProxy {
|
||||||
Self::new(None, &entry, state)
|
Self::new(None, &entry, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "it")]
|
||||||
|
pub fn for_test(state: &Rc<State>) -> Self {
|
||||||
|
Self::new(None, &TEST_CONFIG_ENTRY, state)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_config_dir(state: &Rc<State>) -> Result<Self, ConfigError> {
|
pub fn from_config_dir(state: &Rc<State>) -> Result<Self, ConfigError> {
|
||||||
let dir = match state.config_dir.as_deref() {
|
let dir = match state.config_dir.as_deref() {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
|
|
|
||||||
27
src/it.rs
27
src/it.rs
|
|
@ -1,9 +1,15 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
it::{test_backend::TestBackend, testrun::TestRun, tests::TestCase},
|
it::{
|
||||||
|
test_backend::TestBackend,
|
||||||
|
test_config::{with_test_config, TestConfig},
|
||||||
|
testrun::TestRun,
|
||||||
|
tests::TestCase,
|
||||||
|
},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
futures_util::{future, future::Either},
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
log::Level,
|
log::Level,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -22,6 +28,7 @@ mod test_error;
|
||||||
mod test_object;
|
mod test_object;
|
||||||
pub mod test_backend;
|
pub mod test_backend;
|
||||||
mod test_client;
|
mod test_client;
|
||||||
|
pub mod test_config;
|
||||||
mod test_ifs;
|
mod test_ifs;
|
||||||
mod test_logger;
|
mod test_logger;
|
||||||
mod test_mem;
|
mod test_mem;
|
||||||
|
|
@ -42,7 +49,9 @@ pub fn run_tests() {
|
||||||
failed: Default::default(),
|
failed: Default::default(),
|
||||||
};
|
};
|
||||||
for test in tests::tests() {
|
for test in tests::tests() {
|
||||||
run_test(&it_run, test);
|
with_test_config(|cfg| {
|
||||||
|
run_test(&it_run, test, cfg);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
let failed = it_run.failed.borrow_mut();
|
let failed = it_run.failed.borrow_mut();
|
||||||
if failed.is_not_empty() {
|
if failed.is_not_empty() {
|
||||||
|
|
@ -64,7 +73,7 @@ struct ItRun {
|
||||||
failed: RefCell<AHashMap<&'static str, Vec<String>>>,
|
failed: RefCell<AHashMap<&'static str, Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) {
|
||||||
log::info!("Running {}", test.name());
|
log::info!("Running {}", test.name());
|
||||||
let dir = format!("{}/{}", it_run.path, test.name());
|
let dir = format!("{}/{}", it_run.path, test.name());
|
||||||
std::fs::create_dir_all(&dir).unwrap();
|
std::fs::create_dir_all(&dir).unwrap();
|
||||||
|
|
@ -92,12 +101,20 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
||||||
errors: Default::default(),
|
errors: Default::default(),
|
||||||
server_addr,
|
server_addr,
|
||||||
dir: dir.clone(),
|
dir: dir.clone(),
|
||||||
|
cfg: cfg.clone(),
|
||||||
});
|
});
|
||||||
let errors = errors2.clone();
|
let errors = errors2.clone();
|
||||||
Box::new(async move {
|
Box::new(async move {
|
||||||
let future: Pin<_> = test.run(testrun.clone()).into();
|
let future: Pin<_> = test.run(testrun.clone()).into();
|
||||||
if let Err(e) = future.await {
|
let timeout = state.eng.timeout(5000).unwrap();
|
||||||
testrun.errors.push(e.to_string());
|
match future::select(future, timeout).await {
|
||||||
|
Either::Left((Ok(..), _)) => {}
|
||||||
|
Either::Left((Err(e), _)) => {
|
||||||
|
testrun.errors.push(e.to_string());
|
||||||
|
}
|
||||||
|
Either::Right(..) => {
|
||||||
|
testrun.errors.push("Test timed out".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
errors.set(testrun.errors.take());
|
errors.set(testrun.errors.take());
|
||||||
state.el.stop();
|
state.el.stop();
|
||||||
|
|
|
||||||
127
src/it/test_config.rs
Normal file
127
src/it/test_config.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
use {
|
||||||
|
crate::it::test_error::TestError,
|
||||||
|
isnt::std_1::primitive::IsntConstPtrExt,
|
||||||
|
jay_config::_private::{
|
||||||
|
bincode_ops,
|
||||||
|
ipc::{ClientMessage, ServerMessage},
|
||||||
|
ConfigEntry, VERSION,
|
||||||
|
},
|
||||||
|
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static TEST_CONFIG_ENTRY: ConfigEntry = ConfigEntry {
|
||||||
|
version: VERSION,
|
||||||
|
init,
|
||||||
|
unref,
|
||||||
|
handle_msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
|
static mut CONFIG: *const TestConfig = ptr::null();
|
||||||
|
|
||||||
|
pub fn with_test_config<T, F>(f: F) -> T
|
||||||
|
where
|
||||||
|
F: FnOnce(Rc<TestConfig>) -> T,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let tc = Rc::new(TestConfig {
|
||||||
|
srv: Cell::new(None),
|
||||||
|
});
|
||||||
|
let old = CONFIG;
|
||||||
|
CONFIG = tc.deref();
|
||||||
|
let res = f(tc.clone());
|
||||||
|
CONFIG = old;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init(
|
||||||
|
srv_data: *const u8,
|
||||||
|
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||||
|
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||||
|
_msg: *const u8,
|
||||||
|
_size: usize,
|
||||||
|
) -> *const u8 {
|
||||||
|
let tc = CONFIG;
|
||||||
|
assert!(tc.is_not_null());
|
||||||
|
Rc::increment_strong_count(tc);
|
||||||
|
{
|
||||||
|
let tc = &*tc;
|
||||||
|
tc.srv.set(Some(ServerData {
|
||||||
|
srv_data,
|
||||||
|
srv_unref,
|
||||||
|
srv_handler,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
tc.cast()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn unref(data: *const u8) {
|
||||||
|
Rc::decrement_strong_count(data.cast::<TestConfig>());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||||
|
let _tc = &*data.cast::<TestConfig>();
|
||||||
|
let msg = std::slice::from_raw_parts(msg, size);
|
||||||
|
let res = bincode::decode_from_slice::<ServerMessage, _>(msg, bincode_ops());
|
||||||
|
let (msg, _) = match res {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("could not deserialize message: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match msg {
|
||||||
|
ServerMessage::Configure { .. } => {}
|
||||||
|
ServerMessage::Response { .. } => {}
|
||||||
|
ServerMessage::InvokeShortcut { .. } => {}
|
||||||
|
ServerMessage::NewInputDevice { .. } => {}
|
||||||
|
ServerMessage::DelInputDevice { .. } => {}
|
||||||
|
ServerMessage::ConnectorConnect { .. } => {}
|
||||||
|
ServerMessage::ConnectorDisconnect { .. } => {}
|
||||||
|
ServerMessage::NewConnector { .. } => {}
|
||||||
|
ServerMessage::DelConnector { .. } => {}
|
||||||
|
ServerMessage::TimerExpired { .. } => {}
|
||||||
|
ServerMessage::GraphicsInitialized => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct ServerData {
|
||||||
|
srv_data: *const u8,
|
||||||
|
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||||
|
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TestConfig {
|
||||||
|
srv: Cell<Option<ServerData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestConfig {
|
||||||
|
fn send(&self, msg: ClientMessage) -> Result<(), TestError> {
|
||||||
|
let srv = match self.srv.get() {
|
||||||
|
Some(srv) => srv,
|
||||||
|
_ => bail!("srv not set"),
|
||||||
|
};
|
||||||
|
let mut buf = vec![];
|
||||||
|
bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap();
|
||||||
|
unsafe {
|
||||||
|
(srv.srv_handler)(srv.srv_data, buf.as_ptr(), buf.len());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quit(&self) -> Result<(), TestError> {
|
||||||
|
self.send(ClientMessage::Quit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestConfig {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if let Some(srv) = self.srv.take() {
|
||||||
|
(srv.srv_unref)(srv.srv_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
it::{
|
it::{
|
||||||
test_backend::TestBackend,
|
test_backend::TestBackend,
|
||||||
test_client::TestClient,
|
test_client::TestClient,
|
||||||
|
test_config::TestConfig,
|
||||||
test_error::{TestError, TestErrorExt},
|
test_error::{TestError, TestErrorExt},
|
||||||
test_ifs::test_display::TestDisplay,
|
test_ifs::test_display::TestDisplay,
|
||||||
test_transport::TestTransport,
|
test_transport::TestTransport,
|
||||||
|
|
@ -25,6 +26,7 @@ pub struct TestRun {
|
||||||
pub errors: Stack<String>,
|
pub errors: Stack<String>,
|
||||||
pub server_addr: c::sockaddr_un,
|
pub server_addr: c::sockaddr_un,
|
||||||
pub dir: String,
|
pub dir: String,
|
||||||
|
pub cfg: Rc<TestConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestRun {
|
impl TestRun {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ macro_rules! tassert_eq {
|
||||||
mod t0001_shm_formats;
|
mod t0001_shm_formats;
|
||||||
mod t0002_window;
|
mod t0002_window;
|
||||||
mod t0003_multi_window;
|
mod t0003_multi_window;
|
||||||
|
mod t0004_quit;
|
||||||
|
|
||||||
pub trait TestCase {
|
pub trait TestCase {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
@ -76,5 +77,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||||
t0001_shm_formats,
|
t0001_shm_formats,
|
||||||
t0002_window,
|
t0002_window,
|
||||||
t0003_multi_window,
|
t0003_multi_window,
|
||||||
|
t0004_quit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
src/it/tests/t0004_quit.rs
Normal file
15
src/it/tests/t0004_quit.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use {
|
||||||
|
crate::it::{test_error::TestError, testrun::TestRun},
|
||||||
|
std::{future::pending, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
/// Quit
|
||||||
|
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||||
|
for _ in 0..2 {
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
}
|
||||||
|
run.cfg.quit()?;
|
||||||
|
pending().await
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue