Wrote integration test to test --placement on-host to fix #1. Looks good so far.

This commit is contained in:
Johannes Leupolz 2026-01-20 22:52:09 +00:00
parent fd55bffddb
commit 6e23a02e3f
8 changed files with 80 additions and 27 deletions

View file

@ -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:

View file

@ -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
}

View file

@ -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<VuinputdGuard> = 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);

View file

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

View file

@ -2,7 +2,7 @@
//
// Author: Johannes Leupolz <dev@leupolz.eu>
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()

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {