Now a separate instance of vuinputd with its own device node runs as part of the integration tests.

This commit is contained in:
Johannes Leupolz 2025-12-15 22:38:29 +00:00
parent 16afd2a482
commit 0183da2477
4 changed files with 74 additions and 3 deletions

View file

@ -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 = []

View file

@ -1 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
pub mod bwrap;
pub mod run_vuinputd;

View file

@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
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<VuinputdGuard> = 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();
}
}

View file

@ -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()