From 636604b586aac0ee767b86693ffcc2f59d57bbd8 Mon Sep 17 00:00:00 2001 From: Johannes Leupolz Date: Sat, 22 Nov 2025 21:34:05 +0000 Subject: [PATCH] - Added new test document that documents conducted tests. - Add test for job engine - Fixed a pointer on cleanup --- docs/TESTS.md | 14 ++++++++ vuinputd/src/jobs/closure_job.rs | 10 +++--- vuinputd/src/jobs/mod.rs | 3 ++ vuinputd/src/jobs/tests.rs | 55 ++++++++++++++++++++++++++++++++ vuinputd/src/main.rs | 14 ++++---- 5 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 docs/TESTS.md create mode 100644 vuinputd/src/jobs/tests.rs diff --git a/docs/TESTS.md b/docs/TESTS.md new file mode 100644 index 0000000..ddd8602 --- /dev/null +++ b/docs/TESTS.md @@ -0,0 +1,14 @@ +# Tests + +## Manual end-to-end tests + +| vuinputd | host | input type | app that creates device | app that reads device | working | Notes | +| -------------- | ---------- |---------- | ---------- |---------- |---------- |---------- | +| 0.2.0 | Ubuntu 24.04 amd64 | virtual keyboard | Sunshine (via moonlight-qt 6.1.0 on macos) | labwc via libinput | :white_check_mark: | (1) | +| 0.2.0 | Ubuntu 24.04 amd64| virtual mouse | Sunshine (via moonlight-qt 6.1.0 on macos) | labwc via libinput | :white_check_mark:) | (1) | +| 0.2.0 | Ubuntu 24.04 amd64 | virtual keyboard | Steam (via Remote Play from Mac) | Return to Monkey Island | :white_check_mark: | (2) | +| 0.2.0 | Ubuntu 24.04 amd64 | virtual gamepad | Steam (via Remote Play from Mac) | Return to Monkey Island | :x: | (2) | + + +(1) works also for programs running on the wayland desktop +(2) Steam is a 32-bit application on linux \ No newline at end of file diff --git a/vuinputd/src/jobs/closure_job.rs b/vuinputd/src/jobs/closure_job.rs index fc868a2..9236e94 100644 --- a/vuinputd/src/jobs/closure_job.rs +++ b/vuinputd/src/jobs/closure_job.rs @@ -11,7 +11,7 @@ pub struct ClosureJob { desc: String, execute_after_cancellation: bool, target: JobTarget, - task_creator: Box Pin>> + Send + 'static>, + task_creator: Box Pin>> + Send + 'static>, } impl ClosureJob { @@ -20,7 +20,7 @@ impl ClosureJob { target: JobTarget, execute_after_cancellation: bool, f: Box< - dyn Fn(JobTarget) -> Pin>> // closure returns any future + dyn Fn(&ClosureJob) -> Pin>> // closure returns any future + Send // the closure itself can be sent across threads + 'static, >, @@ -46,8 +46,7 @@ impl Job for ClosureJob { fn create_task(self: &ClosureJob) -> Pin>> { let creator = &self.task_creator; - let target = self.job_target(); - let task = creator(target); + let task = creator(self); task } @@ -66,7 +65,8 @@ pub fn example() { "Host maintenance", JobTarget::Host, false, - Box::new(|target| { + Box::new(|job: &ClosureJob| { + let target = job.target.clone(); Box::pin(async move { println!("Running host job on {:?}", target); }) diff --git a/vuinputd/src/jobs/mod.rs b/vuinputd/src/jobs/mod.rs index 39588ac..3639120 100644 --- a/vuinputd/src/jobs/mod.rs +++ b/vuinputd/src/jobs/mod.rs @@ -33,3 +33,6 @@ pub mod closure_job; pub mod job; + +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/vuinputd/src/jobs/tests.rs b/vuinputd/src/jobs/tests.rs new file mode 100644 index 0000000..45d8f26 --- /dev/null +++ b/vuinputd/src/jobs/tests.rs @@ -0,0 +1,55 @@ +use crate::jobs::closure_job::ClosureJob; +use crate::jobs::job::{Dispatcher, Job, JobTarget}; + +use super::*; +use futures::executor::LocalPool; +use futures::task::LocalSpawnExt; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::{Arc, Mutex}; + +/// Simple shared integer counter +fn shared_counter() -> Arc> { + Arc::new(Mutex::new(0)) +} + +// +// 1. Ordering test +// +#[test] +fn test_job_ordering() { + let mut dispatcher = Dispatcher::new(); + let c = shared_counter(); + + let c1 = c.clone(); + dispatcher.dispatch(Box::new(ClosureJob::new( + "set to 5", + JobTarget::Host, + false, + Box::new(move |_job| { + let c1 = c1.clone(); + Box::pin(async move { + *c1.lock().unwrap() = 5; + }) + }), + ))); + + + // job 2: increment to 6 + let c2 = c.clone(); + dispatcher.dispatch(Box::new(ClosureJob::new( + "increment to 6", + JobTarget::Host, + false, + Box::new(move |_job| { + let c2 = c2.clone(); + Box::pin(async move { + *c2.lock().unwrap() += 1; + }) + }), + ))); + + dispatcher.wait_until_finished(); + + assert_eq!(*c.lock().unwrap(), 6); +} diff --git a/vuinputd/src/main.rs b/vuinputd/src/main.rs index cb47a7b..7ea18a3 100644 --- a/vuinputd/src/main.rs +++ b/vuinputd/src/main.rs @@ -742,15 +742,15 @@ fn check_permissions() -> Result<(), std::io::Error> { fn main() -> std::io::Result<()> { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init(); - check_permissions().unwrap(); + check_permissions().expect("failed to read the capabilities of the vuinputd process");; let args: Vec = std::env::args().collect(); - VUINPUT_STATE.set(RwLock::new(HashMap::new())).unwrap(); - VUINPUT_COUNTER.set(AtomicU64::new(3)).unwrap(); - JOB_DISPATCHER.set(Mutex::new(Dispatcher::new())).unwrap(); - VUINPUTD_NAMESPACES.set(get_namespace(Pid::SelfPid)).unwrap(); - DEDUP_LAST_ERROR.set(Mutex::new(None)).unwrap(); + VUINPUT_STATE.set(RwLock::new(HashMap::new())).expect("failed to initialize global state"); + VUINPUT_COUNTER.set(AtomicU64::new(3)).expect("failed to initialize the counter that provides the values of the CUSE file handles"); // 3, because 1 and 2 are usually STDOUT and STDERR + JOB_DISPATCHER.set(Mutex::new(Dispatcher::new())).expect("failed to initialize the job dispatcher"); + VUINPUTD_NAMESPACES.set(get_namespace(Pid::SelfPid)).expect("failed to retrieve the namespaces of the vuinputd process"); + DEDUP_LAST_ERROR.set(Mutex::new(None)).expect("failed to initialize the log deduplication state"); JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(MonitorBackgroundLoop::new())); info!("Starting vuinputd"); @@ -799,7 +799,7 @@ fn main() -> std::io::Result<()> { ); let _reclaim_arg_program_name = CString::from_raw(parg_program_name); let _reclaim_arg_foreground = CString::from_raw(parg_foreground); - let _reclaim_arg_foreground = CString::from_raw(parg_singlethreaded); + let _reclaim_arg_singlethreaded = CString::from_raw(parg_singlethreaded); } info!("Stopping vuinputd"); JOB_DISPATCHER.get().unwrap().lock().unwrap().close();