ci(lesavka): stabilize media gate contracts
This commit is contained in:
parent
8ed19c4311
commit
5b55c85263
@ -10,11 +10,28 @@ use lesavka_server::uvc_runtime::{pick_uvc_device, supervise_uvc_control};
|
|||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
use std::path::Path;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use temp_env::{with_var, with_vars};
|
use temp_env::{with_var, with_vars};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use tokio::runtime::Runtime;
|
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]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn supervise_uvc_control_starts_helper_when_device_is_set() {
|
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(
|
fs::write(
|
||||||
&helper,
|
&helper,
|
||||||
format!(
|
format!(
|
||||||
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\n",
|
"#!/usr/bin/env bash\nset -euo pipefail\necho \"$*\" >> '{}'\nsleep 0.05\n",
|
||||||
marker.display()
|
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");
|
fs::set_permissions(&helper, perms).expect("chmod helper script");
|
||||||
|
|
||||||
let helper_path = helper.to_string_lossy().to_string();
|
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 rt = Runtime::new().expect("runtime");
|
||||||
let result = rt.block_on(async {
|
rt.block_on(async {
|
||||||
tokio::time::timeout(
|
let supervisor = tokio::spawn(supervise_uvc_control(helper_path));
|
||||||
Duration::from_millis(350),
|
let calls = wait_for_marker(&marker, |contents| {
|
||||||
supervise_uvc_control(helper_path),
|
contents.contains("--device /dev/video-loop")
|
||||||
)
|
})
|
||||||
.await
|
.await;
|
||||||
});
|
supervisor.abort();
|
||||||
assert!(result.is_err(), "supervisor should still be running");
|
let _ = supervisor.await;
|
||||||
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
|
calls
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let calls = fs::read_to_string(marker).expect("read helper marker");
|
|
||||||
assert!(
|
assert!(
|
||||||
calls.contains("--device /dev/video-loop"),
|
calls.contains("--device /dev/video-loop"),
|
||||||
"expected helper to receive device args, got: {calls}"
|
"expected helper to receive device args, got: {calls}"
|
||||||
@ -64,7 +83,7 @@ fn supervise_uvc_control_restarts_helper_after_exit() {
|
|||||||
fs::write(
|
fs::write(
|
||||||
&helper,
|
&helper,
|
||||||
format!(
|
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()
|
marker.display()
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -76,25 +95,31 @@ fn supervise_uvc_control_restarts_helper_after_exit() {
|
|||||||
fs::set_permissions(&helper, perms).expect("chmod helper script");
|
fs::set_permissions(&helper, perms).expect("chmod helper script");
|
||||||
|
|
||||||
let helper_path = helper.to_string_lossy().to_string();
|
let helper_path = helper.to_string_lossy().to_string();
|
||||||
with_vars(
|
let calls = with_vars(
|
||||||
[
|
[
|
||||||
("LESAVKA_UVC_DEV", Some("/dev/video-loop")),
|
("LESAVKA_UVC_DEV", Some("/dev/video-loop")),
|
||||||
("LESAVKA_UVC_RESTART_DELAY_MS", Some("25")),
|
("LESAVKA_UVC_RESTART_DELAY_MS", Some("25")),
|
||||||
],
|
],
|
||||||
|| {
|
|| {
|
||||||
let rt = Runtime::new().expect("runtime");
|
let rt = Runtime::new().expect("runtime");
|
||||||
let result = rt.block_on(async {
|
rt.block_on(async {
|
||||||
tokio::time::timeout(
|
let supervisor = tokio::spawn(supervise_uvc_control(helper_path));
|
||||||
Duration::from_millis(450),
|
let calls = wait_for_marker(&marker, |contents| {
|
||||||
supervise_uvc_control(helper_path),
|
contents
|
||||||
)
|
.lines()
|
||||||
.await
|
.filter(|line| line.contains("--device /dev/video-loop"))
|
||||||
});
|
.count()
|
||||||
assert!(result.is_err(), "supervisor should still be running");
|
>= 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
|
let restart_count = calls
|
||||||
.lines()
|
.lines()
|
||||||
.filter(|line| line.contains("--device /dev/video-loop"))
|
.filter(|line| line.contains("--device /dev/video-loop"))
|
||||||
|
|||||||
@ -102,6 +102,7 @@ mod camera_include_contract {
|
|||||||
| "vulkanh264enc"
|
| "vulkanh264enc"
|
||||||
| "vaapih264enc"
|
| "vaapih264enc"
|
||||||
| "v4l2h264enc"
|
| "v4l2h264enc"
|
||||||
|
| "x264enc"
|
||||||
| "missing-hardware-h264enc"
|
| "missing-hardware-h264enc"
|
||||||
),
|
),
|
||||||
"unexpected encoder: {enc}"
|
"unexpected encoder: {enc}"
|
||||||
@ -111,7 +112,7 @@ mod camera_include_contract {
|
|||||||
assert!(
|
assert!(
|
||||||
matches!(
|
matches!(
|
||||||
enc,
|
enc,
|
||||||
"nvh264enc" | "vulkanh264enc" | "vaapih264enc" | "v4l2h264enc"
|
"nvh264enc" | "vulkanh264enc" | "vaapih264enc" | "v4l2h264enc" | "x264enc"
|
||||||
),
|
),
|
||||||
"unexpected encoder: {enc}"
|
"unexpected encoder: {enc}"
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user