From 6e23a02e3fd67a93e4b937d030abcf4c1b64f542 Mon Sep 17 00:00:00 2001 From: Johannes Leupolz Date: Tue, 20 Jan 2026 22:52:09 +0000 Subject: [PATCH] Wrote integration test to test --placement on-host to fix #1. Looks good so far. --- docs/TESTS.md | 9 +++++ vuinputd-tests/src/bwrap.rs | 5 ++- vuinputd-tests/src/run_vuinputd.rs | 40 ++++++++++++---------- vuinputd-tests/tests/integration_tests.rs | 41 +++++++++++++++++++++-- vuinputd-tests/tests/podman_tests.rs | 6 ++-- vuinputd/src/jobs/emit_udev_event_job.rs | 2 +- vuinputd/src/jobs/mknod_device_job.rs | 2 +- vuinputd/src/jobs/remove_device_job.rs | 2 +- 8 files changed, 80 insertions(+), 27 deletions(-) diff --git a/docs/TESTS.md b/docs/TESTS.md index e68222a..1400ea2 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -2,6 +2,15 @@ ## Integration tests +Ensure, you have a `/run/vuinputd/vuinput-test`-folder that allows the usage of character devices: +``` +mkdir -p /run/vuinputd/vuinput-test +mount -t tmpfs -o mode=755,size=1M tmpfs /run/vuinputd/vuinput-test +mkdir -p /run/vuinputd/vuinput-test/dev +mkdir -p /run/vuinputd/vuinput-test/dev-input +mkdir -p /run/vuinputd/vuinput-test/udev +``` + ### With bubblewrap Install bubblewrap: diff --git a/vuinputd-tests/src/bwrap.rs b/vuinputd-tests/src/bwrap.rs index 8ccdcbe..a777efc 100644 --- a/vuinputd-tests/src/bwrap.rs +++ b/vuinputd-tests/src/bwrap.rs @@ -58,8 +58,11 @@ impl BwrapBuilder { // So, we mount a temporary directory that does not have this restrictions. self.args.extend([ "--dev-bind".into(), - "/dev/tmp/vuinputd-test".into(), + "/run/vuinputd/vuinput-test/dev".into(), "/dev".into(), + "--dev-bind".into(), + "/run/vuinputd/vuinput-test/dev-input".into(), + "/dev/input".into(), ]); self } diff --git a/vuinputd-tests/src/run_vuinputd.rs b/vuinputd-tests/src/run_vuinputd.rs index e5241f4..08397bb 100644 --- a/vuinputd-tests/src/run_vuinputd.rs +++ b/vuinputd-tests/src/run_vuinputd.rs @@ -5,7 +5,7 @@ use std::{ os::unix::process::CommandExt, process::{Child, Command}, - sync::OnceLock, + sync::Mutex, thread, time::Duration, }; @@ -14,33 +14,37 @@ use nix::sys::signal::{self, Signal}; use nix::unistd::Pid; /// Global singleton -static VUINPUTD: OnceLock = OnceLock::new(); +static VUINPUTD_LOCK: Mutex<()> = Mutex::new(()); -pub fn ensure_vuinputd_running() { - VUINPUTD.get_or_init(|| VuinputdGuard::start()); +pub fn ensure_vuinputd_running(args: &[&str]) -> VuinputdGuard { + VuinputdGuard::start(args) } -struct VuinputdGuard { +pub struct VuinputdGuard { child: Child, } impl VuinputdGuard { - fn start() -> Self { + fn start(args: &[&str]) -> Self { + println!("Acquiring lock to ensure only one vuinputd test instance is running"); + let _mutex = VUINPUTD_LOCK.lock().unwrap(); println!("Executing vuinputd located via cargo run"); + let mut concat_args = vec![ + "run", + "-p", + "vuinputd", + "--", + "--major", + "120", + "--minor", + "414796", + "--devname", + "vuinput-test", + ]; + concat_args.extend(args); let child = unsafe { Command::new("cargo") - .args([ - "run", - "-p", - "vuinputd", - "--", - "--major", - "120", - "--minor", - "414796", - "--devname", - "vuinputd-test", - ]) + .args(concat_args) .pre_exec(|| { // Last resort, if the parent just is killed. libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); diff --git a/vuinputd-tests/tests/integration_tests.rs b/vuinputd-tests/tests/integration_tests.rs index 6100df1..4e96b58 100644 --- a/vuinputd-tests/tests/integration_tests.rs +++ b/vuinputd-tests/tests/integration_tests.rs @@ -127,8 +127,8 @@ fn test_keyboard_in_container_with_uinput() { feature = "requires-bwrap" ))] #[test] -fn test_keyboard_in_container_with_vuinput() { - run_vuinputd::ensure_vuinputd_running(); +fn test_keyboard_in_container_with_vuinput_placement_in_container() { + let _guard: run_vuinputd::VuinputdGuard=run_vuinputd::ensure_vuinputd_running(&[]); let test_keyboard = env!("CARGO_BIN_EXE_test-keyboard"); @@ -156,3 +156,40 @@ fn test_keyboard_in_container_with_vuinput() { assert!(out.status.success()); } + +#[cfg(all( + feature = "requires-privileges", + feature = "requires-uinput", + feature = "requires-bwrap" +))] +#[test] +fn test_keyboard_in_container_with_vuinput_placement_on_host() { + let _guard=run_vuinputd::ensure_vuinputd_running(&["--placement","on-host"]); + + let test_keyboard = env!("CARGO_BIN_EXE_test-keyboard"); + + let (builder, _ipc) = bwrap::BwrapBuilder::new() + .unshare_net() + .ro_bind("/", "/") + .tmpfs("/tmp") + // dev needs to be writable for the new devices + .dev() + // run needs to be writable for the udev devices + .tmpfs("/run") + .bind("/run/vuinputd/vuinput-test/udev", "/run/udev") + .dev_bind("/dev/vuinput-test", "/dev/uinput") + .die_with_parent() + .with_ipc() + .expect("failed to create IPC"); + + let out = builder + .command(test_keyboard, &["--ipc"]) + .run() + .unwrap_or_else(|e| panic!("failed to run bwrap!: {e}")); + + println!("Output"); + println!("stdout: {}", str::from_utf8(&out.stdout).unwrap()); + println!("stderr: {}", str::from_utf8(&out.stderr).unwrap()); + + assert!(out.status.success()); +} diff --git a/vuinputd-tests/tests/podman_tests.rs b/vuinputd-tests/tests/podman_tests.rs index bf974fe..291d2c1 100644 --- a/vuinputd-tests/tests/podman_tests.rs +++ b/vuinputd-tests/tests/podman_tests.rs @@ -2,7 +2,7 @@ // // Author: Johannes Leupolz -use std::{process::Command, time::Duration}; +use std::time::Duration; use vuinputd_tests::podman; use vuinputd_tests::run_vuinputd; @@ -66,9 +66,9 @@ fn test_podman_ipc() { ))] #[test] fn test_keyboard_in_container_with_vuinput() { - run_vuinputd::ensure_vuinputd_running(); + let _guard=run_vuinputd::ensure_vuinputd_running(&[]); - let (builder, ipc) = podman::PodmanBuilder::new() + let (builder, _ipc) = podman::PodmanBuilder::new() .run_cmd() .rm() .with_ipc() diff --git a/vuinputd/src/jobs/emit_udev_event_job.rs b/vuinputd/src/jobs/emit_udev_event_job.rs index a441d81..6132230 100644 --- a/vuinputd/src/jobs/emit_udev_event_job.rs +++ b/vuinputd/src/jobs/emit_udev_event_job.rs @@ -83,7 +83,7 @@ impl EmitUdevEventJob { impl Job for EmitUdevEventJob { fn desc(&self) -> &str { - "emit udev event into container" + "emit udev event" } fn execute_after_cancellation(&self) -> bool { diff --git a/vuinputd/src/jobs/mknod_device_job.rs b/vuinputd/src/jobs/mknod_device_job.rs index 1146a36..6b63963 100644 --- a/vuinputd/src/jobs/mknod_device_job.rs +++ b/vuinputd/src/jobs/mknod_device_job.rs @@ -77,7 +77,7 @@ impl MknodDeviceJob { impl Job for MknodDeviceJob { fn desc(&self) -> &str { - "mknod input device in container" + "mknod input device" } fn execute_after_cancellation(&self) -> bool { diff --git a/vuinputd/src/jobs/remove_device_job.rs b/vuinputd/src/jobs/remove_device_job.rs index 4e76260..9097899 100644 --- a/vuinputd/src/jobs/remove_device_job.rs +++ b/vuinputd/src/jobs/remove_device_job.rs @@ -79,7 +79,7 @@ impl RemoveDeviceJob { impl Job for RemoveDeviceJob { fn desc(&self) -> &str { - "Remove input device from container" + "Remove input device" } fn execute_after_cancellation(&self) -> bool {