ci(lesavka): stabilize media gate contracts

This commit is contained in:
Brad Stein 2026-05-18 15:37:13 -03:00
parent 8ed19c4311
commit 5b55c85263
2 changed files with 49 additions and 23 deletions

View File

@ -10,11 +10,28 @@ use lesavka_server::uvc_runtime::{pick_uvc_device, supervise_uvc_control};
use serial_test::serial;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::time::Duration;
use temp_env::{with_var, with_vars};
use tempfile::tempdir;
use tokio::runtime::Runtime;
async fn wait_for_marker(marker: &Path, is_ready: impl Fn(&str) -> bool) -> String {
let deadline = tokio::time::Instant::now() + Duration::from_secs(2);
loop {
if let Ok(contents) = fs::read_to_string(marker) {
if is_ready(&contents) {
return contents;
}
}
assert!(
tokio::time::Instant::now() < deadline,
"helper marker was not written in time"
);
tokio::time::sleep(Duration::from_millis(20)).await;
}
}
#[test]
#[serial]
fn supervise_uvc_control_starts_helper_when_device_is_set() {
@ -24,7 +41,7 @@ fn supervise_uvc_control_starts_helper_when_device_is_set() {
fs::write(
&helper,
format!(
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\n",
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\nsleep 0.05\n",
marker.display()
),
)
@ -36,19 +53,21 @@ fn supervise_uvc_control_starts_helper_when_device_is_set() {
fs::set_permissions(&helper, perms).expect("chmod helper script");
let helper_path = helper.to_string_lossy().to_string();
with_var("LESAVKA_UVC_DEV", Some("/dev/video-loop"), || {
let calls = with_var("LESAVKA_UVC_DEV", Some("/dev/video-loop"), || {
let rt = Runtime::new().expect("runtime");
let result = rt.block_on(async {
tokio::time::timeout(
Duration::from_millis(350),
supervise_uvc_control(helper_path),
)
.await
});
assert!(result.is_err(), "supervisor should still be running");
rt.block_on(async {
let supervisor = tokio::spawn(supervise_uvc_control(helper_path));
let calls = wait_for_marker(&marker, |contents| {
contents.contains("--device /dev/video-loop")
})
.await;
supervisor.abort();
let _ = supervisor.await;
tokio::time::sleep(Duration::from_millis(100)).await;
calls
})
});
let calls = fs::read_to_string(marker).expect("read helper marker");
assert!(
calls.contains("--device /dev/video-loop"),
"expected helper to receive device args, got: {calls}"
@ -64,7 +83,7 @@ fn supervise_uvc_control_restarts_helper_after_exit() {
fs::write(
&helper,
format!(
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\nexit 0\n",
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\nsleep 0.05\nexit 0\n",
marker.display()
),
)
@ -76,25 +95,31 @@ fn supervise_uvc_control_restarts_helper_after_exit() {
fs::set_permissions(&helper, perms).expect("chmod helper script");
let helper_path = helper.to_string_lossy().to_string();
with_vars(
let calls = with_vars(
[
("LESAVKA_UVC_DEV", Some("/dev/video-loop")),
("LESAVKA_UVC_RESTART_DELAY_MS", Some("25")),
],
|| {
let rt = Runtime::new().expect("runtime");
let result = rt.block_on(async {
tokio::time::timeout(
Duration::from_millis(450),
supervise_uvc_control(helper_path),
)
.await
});
assert!(result.is_err(), "supervisor should still be running");
rt.block_on(async {
let supervisor = tokio::spawn(supervise_uvc_control(helper_path));
let calls = wait_for_marker(&marker, |contents| {
contents
.lines()
.filter(|line| line.contains("--device /dev/video-loop"))
.count()
>= 2
})
.await;
supervisor.abort();
let _ = supervisor.await;
tokio::time::sleep(Duration::from_millis(100)).await;
calls
})
},
);
let calls = fs::read_to_string(marker).expect("read helper marker");
let restart_count = calls
.lines()
.filter(|line| line.contains("--device /dev/video-loop"))

View File

@ -102,6 +102,7 @@ mod camera_include_contract {
| "vulkanh264enc"
| "vaapih264enc"
| "v4l2h264enc"
| "x264enc"
| "missing-hardware-h264enc"
),
"unexpected encoder: {enc}"
@ -111,7 +112,7 @@ mod camera_include_contract {
assert!(
matches!(
enc,
"nvh264enc" | "vulkanh264enc" | "vaapih264enc" | "v4l2h264enc"
"nvh264enc" | "vulkanh264enc" | "vaapih264enc" | "v4l2h264enc" | "x264enc"
),
"unexpected encoder: {enc}"
);