2026-04-13 02:52:32 -03:00
|
|
|
//! Integration coverage for `lesavka-uvc` process startup parsing.
|
|
|
|
|
//!
|
|
|
|
|
//! Scope: launch the real `lesavka-uvc` binary with controlled arguments and
|
|
|
|
|
//! environment overrides to exercise argument/config parsing and early startup.
|
|
|
|
|
//! Targets: `server/src/bin/lesavka-uvc.rs`.
|
|
|
|
|
//! Why: command-line/environment startup behavior should fail fast and remain
|
|
|
|
|
//! deterministic without a physical UVC gadget node in CI.
|
|
|
|
|
|
|
|
|
|
use serial_test::serial;
|
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
use std::process::{Child, Command, ExitStatus};
|
|
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
|
use tempfile::NamedTempFile;
|
|
|
|
|
|
|
|
|
|
fn candidate_dirs() -> Vec<PathBuf> {
|
|
|
|
|
let exe = std::env::current_exe().expect("current exe path");
|
|
|
|
|
let mut dirs = Vec::new();
|
|
|
|
|
if let Some(parent) = exe.parent() {
|
|
|
|
|
dirs.push(parent.to_path_buf());
|
|
|
|
|
if let Some(grand) = parent.parent() {
|
|
|
|
|
dirs.push(grand.to_path_buf());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dirs.push(PathBuf::from("target/debug"));
|
|
|
|
|
dirs.push(PathBuf::from("target/llvm-cov-target/debug"));
|
|
|
|
|
dirs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_binary(name: &str) -> Option<PathBuf> {
|
|
|
|
|
candidate_dirs()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|dir| dir.join(name))
|
|
|
|
|
.find(|path| path.exists() && path.is_file())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn wait_for_exit(mut child: Child, timeout: Duration) -> ExitStatus {
|
|
|
|
|
let deadline = Instant::now() + timeout;
|
|
|
|
|
loop {
|
|
|
|
|
if let Some(status) = child.try_wait().expect("poll child") {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
if Instant::now() >= deadline {
|
|
|
|
|
let _ = child.kill();
|
|
|
|
|
let _ = child.wait();
|
|
|
|
|
panic!("lesavka-uvc did not exit within timeout");
|
|
|
|
|
}
|
|
|
|
|
std::thread::sleep(Duration::from_millis(50));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn uvc_binary_requires_device_argument_or_env() {
|
|
|
|
|
let Some(bin) = find_binary("lesavka-uvc") else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let status = Command::new(Path::new(&bin))
|
|
|
|
|
.env_remove("LESAVKA_UVC_DEV")
|
|
|
|
|
.status()
|
|
|
|
|
.expect("spawn lesavka-uvc");
|
2026-04-14 23:03:18 -03:00
|
|
|
assert!(
|
|
|
|
|
!status.success(),
|
|
|
|
|
"uvc binary should fail without a device path"
|
|
|
|
|
);
|
2026-04-13 02:52:32 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn uvc_binary_applies_env_config_and_fails_fast_on_non_v4l2_node() {
|
|
|
|
|
let Some(bin) = find_binary("lesavka-uvc") else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let fake_device = NamedTempFile::new().expect("temp device");
|
|
|
|
|
let child = Command::new(Path::new(&bin))
|
|
|
|
|
.arg("--device")
|
|
|
|
|
.arg(fake_device.path())
|
|
|
|
|
.env("LESAVKA_UVC_MAXPAYLOAD_LIMIT", "256")
|
|
|
|
|
.env("LESAVKA_UVC_MAXPACKET", "4096")
|
|
|
|
|
.env("LESAVKA_UVC_BULK", "1")
|
|
|
|
|
.env("LESAVKA_UVC_FPS", "30")
|
|
|
|
|
.spawn()
|
|
|
|
|
.expect("spawn lesavka-uvc");
|
|
|
|
|
|
|
|
|
|
let status = wait_for_exit(child, Duration::from_secs(3));
|
|
|
|
|
assert!(
|
|
|
|
|
!status.success(),
|
|
|
|
|
"uvc binary should fail on non-v4l2 test file"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn uvc_binary_accepts_positional_device_argument() {
|
|
|
|
|
let Some(bin) = find_binary("lesavka-uvc") else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let fake_device = NamedTempFile::new().expect("temp device");
|
|
|
|
|
let child = Command::new(Path::new(&bin))
|
|
|
|
|
.arg(fake_device.path())
|
|
|
|
|
.env_remove("LESAVKA_UVC_BULK")
|
|
|
|
|
.env("LESAVKA_UVC_MAXPAYLOAD_LIMIT", "2048")
|
|
|
|
|
.env("LESAVKA_UVC_MAXPACKET", "1024")
|
|
|
|
|
.spawn()
|
|
|
|
|
.expect("spawn lesavka-uvc");
|
|
|
|
|
|
|
|
|
|
let status = wait_for_exit(child, Duration::from_secs(3));
|
|
|
|
|
assert!(
|
|
|
|
|
!status.success(),
|
|
|
|
|
"uvc binary should fail on non-v4l2 test file"
|
|
|
|
|
);
|
|
|
|
|
}
|