diff --git a/vuinputd-tests/Cargo.toml b/vuinputd-tests/Cargo.toml index 70ae4bc..0bdd7b3 100644 --- a/vuinputd-tests/Cargo.toml +++ b/vuinputd-tests/Cargo.toml @@ -11,9 +11,10 @@ name = "bwrap-ipc" [dependencies] uinput-ioctls = { path = "../uinput-ioctls" } -nix = { version = "0.30", features = ["ioctl","socket"] } # ioctl & libc bindings +nix = { version = "0.30", features = ["ioctl","socket","signal"] } # ioctl & libc bindings libc = "0.2" # raw system calls libudev = "0.3" # enumerate-udev +vuinputd = { path = "../vuinputd" } [features] requires-root = [] diff --git a/vuinputd-tests/src/lib.rs b/vuinputd-tests/src/lib.rs index 238911a..5ca94c5 100644 --- a/vuinputd-tests/src/lib.rs +++ b/vuinputd-tests/src/lib.rs @@ -1 +1,6 @@ +// SPDX-License-Identifier: MIT +// +// Author: Johannes Leupolz + pub mod bwrap; +pub mod run_vuinputd; diff --git a/vuinputd-tests/src/run_vuinputd.rs b/vuinputd-tests/src/run_vuinputd.rs new file mode 100644 index 0000000..be2ea99 --- /dev/null +++ b/vuinputd-tests/src/run_vuinputd.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// +// Author: Johannes Leupolz + +use std::{ + process::{Child, Command}, + sync::OnceLock, + time::Duration, + thread, +}; + +use nix::sys::signal::{self,Signal}; +use nix::unistd::Pid; + +/// Global singleton +static VUINPUTD: OnceLock = OnceLock::new(); + +pub fn ensure_vuinputd_running() { + VUINPUTD.get_or_init(|| { + VuinputdGuard::start() + }); +} + +struct VuinputdGuard { + child: Child, +} + +impl VuinputdGuard { + fn start() -> Self { + println!("Executing vuinputd located via cargo run"); + let child = Command::new("cargo") + .args(["run", "-p", "vuinputd", "--","--major","120","--minor","414796","--devname","vuinputd-test"]) + // adjust args/env if needed + .spawn() + .expect("failed to start vuinputd"); + + // Optional: give it time to create /dev/vuinput + thread::sleep(Duration::from_millis(300)); + + Self { child } + } +} + +impl Drop for VuinputdGuard { + fn drop(&mut self) { + let pid = Pid::from_raw(self.child.id() as i32); + + // First: SIGTERM + let _ = signal::kill(pid, Signal::SIGTERM); + + // Wait a bit + for _ in 0..10 { + if let Ok(Some(_)) = self.child.try_wait() { + return; + } + thread::sleep(Duration::from_millis(100)); + } + + // Still alive → SIGKILL + let _ = signal::kill(pid, Signal::SIGKILL); + let _ = self.child.wait(); + } +} diff --git a/vuinputd-tests/tests/integration_tests.rs b/vuinputd-tests/tests/integration_tests.rs index 915136d..0c95947 100644 --- a/vuinputd-tests/tests/integration_tests.rs +++ b/vuinputd-tests/tests/integration_tests.rs @@ -4,6 +4,7 @@ use std::{process::Command, time::Duration}; use vuinputd_tests::bwrap; +use vuinputd_tests::run_vuinputd; #[cfg(all(feature = "requires-root", feature = "requires-bwrap"))] #[test] @@ -97,7 +98,8 @@ fn test_keyboard_in_container_with_uinput() { #[cfg(all(feature = "requires-root", feature = "requires-uinput", feature = "requires-bwrap"))] #[test] fn test_keyboard_in_container_with_vuinput() { - println!("Note that vuinputd needs to run for this test"); + run_vuinputd::ensure_vuinputd_running(); + let keyboard_in_container = env!("CARGO_BIN_EXE_keyboard-in-container"); let out = bwrap::BwrapBuilder::new() @@ -108,7 +110,7 @@ fn test_keyboard_in_container_with_vuinput() { .tmpfs("/dev") // run needs to be writable for the udev devices .tmpfs("/run") - .dev_bind("/dev/vuinput", "/dev/uinput") + .dev_bind("/dev/vuinput-test", "/dev/uinput") .die_with_parent() .command(keyboard_in_container,&[]) .run()