test(video): enforce downstream coverage gate

This commit is contained in:
Brad Stein 2026-04-21 15:34:46 -03:00
parent c17777b831
commit a50560ccd1
6 changed files with 126 additions and 6 deletions

View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Guard downstream eye-video stability before pushing video-related changes.
set -euo pipefail
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
cd "$ROOT"
VIDEO_TESTS=(
--test video_downstream_feed_contract
--test server_video_include_contract
--test video_support_contract
--test client_output_video_include_contract
--test server_video_sinks_include_contract
--test server_video_sink_smoke_contract
)
VIDEO_IGNORE_REGEX='(/common/src/(hid|paste|process_metrics)\.rs|/server/src/(audio|camera|gadget|paste|runtime_support|uvc_runtime)\.rs)'
cargo fmt --all -- --check
cargo check -q --bin lesavka-client --bin lesavka-server
cargo test -q -p lesavka_testing "${VIDEO_TESTS[@]}"
cargo llvm-cov clean --workspace
cargo llvm-cov --workspace "${VIDEO_TESTS[@]}" \
--ignore-filename-regex "$VIDEO_IGNORE_REGEX" \
--fail-under-lines 95 \
--summary-only

View File

@ -336,12 +336,17 @@ pub async fn eye_ball_with_request(
let pipeline = gst::Pipeline::new();
let (tx, rx) = tokio::sync::mpsc::channel(64);
for seq in 0..8 {
let _ = tx.try_send(Ok(VideoPacket {
id: id.min(1),
pts: 0,
pts: seq * 16_666,
data: vec![0, 0, 0, 1, 0x65, 0x88, 0x84],
seq: seq + 1,
effective_fps: 60,
server_encoder_label: "coverage-testsrc".to_string(),
..Default::default()
}));
}
Ok(VideoStream {
_pipeline: pipeline,

View File

@ -95,6 +95,33 @@ mod video_include_contract {
with_var("PATH", Some(merged), f);
}
#[test]
#[serial]
fn h264_decoder_selection_honors_env_and_fallbacks() {
gst::init().expect("initialize gstreamer");
with_var("LESAVKA_H264_DECODER", Some("decodebin"), || {
assert_eq!(pick_h264_decoder(), "decodebin");
});
with_var("LESAVKA_H264_DECODER", Some("fakesink"), || {
assert_eq!(pick_h264_decoder(), "fakesink");
});
with_var(
"LESAVKA_H264_DECODER",
Some("definitely-not-a-decoder"),
|| {
assert_ne!(pick_h264_decoder(), "definitely-not-a-decoder");
},
);
with_var("LESAVKA_H264_DECODER", Some(" "), || {
assert!(!pick_h264_decoder().trim().is_empty());
});
with_var("LESAVKA_H264_DECODER", None::<&str>, || {
assert!(!pick_h264_decoder().trim().is_empty());
});
assert!(buildable_decoder("fakesink"));
assert!(!buildable_decoder("definitely-not-a-real-gst-element"));
}
#[test]
#[serial]
fn monitor_window_new_covers_x11_backend_path() {

View File

@ -31,6 +31,30 @@ mod video_include_contract {
let _ = gst::init();
}
#[test]
fn eye_profile_and_telemetry_helpers_are_stable() {
assert_eq!(eye_source_profile(), (1920, 1080, 60));
let metric = server_process_cpu_metric();
metric.store(123, std::sync::atomic::Ordering::Relaxed);
assert_eq!(metric.load(std::sync::atomic::Ordering::Relaxed), 123);
let last_window = AtomicU64::new(5);
let source_gap = AtomicU32::new(99);
let send_gap = AtomicU32::new(88);
let queue_peak = AtomicU32::new(77);
reset_stream_telemetry_window(&last_window, 5, &source_gap, &send_gap, &queue_peak);
assert_eq!(source_gap.load(Ordering::Relaxed), 99);
assert_eq!(send_gap.load(Ordering::Relaxed), 88);
assert_eq!(queue_peak.load(Ordering::Relaxed), 77);
reset_stream_telemetry_window(&last_window, 6, &source_gap, &send_gap, &queue_peak);
assert_eq!(source_gap.load(Ordering::Relaxed), 0);
assert_eq!(send_gap.load(Ordering::Relaxed), 0);
assert_eq!(queue_peak.load(Ordering::Relaxed), 0);
}
#[tokio::test]
async fn video_stream_forwards_inner_packets() {
init_gst();
@ -248,4 +272,24 @@ mod video_include_contract {
});
});
}
#[test]
#[serial]
fn wait_for_eye_device_reports_non_character_paths() {
let rt = tokio::runtime::Runtime::new().expect("runtime");
let dir = tempfile::tempdir().expect("tempdir");
let regular_file = dir.path().join("not-a-video-device");
std::fs::write(&regular_file, "not a device").expect("write marker file");
with_var("LESAVKA_EYE_DEVICE_WAIT_MS", Some("50"), || {
with_var("LESAVKA_EYE_DEVICE_POLL_MS", Some("25"), || {
rt.block_on(async {
let err = wait_for_eye_device(regular_file.to_str().expect("utf8 path"), "l")
.await
.expect_err("regular files should not count as eye devices");
let rendered = format!("{err:#}");
assert!(rendered.contains("not a character device"));
});
});
});
}
}

View File

@ -49,6 +49,22 @@ fn native_downstream_eye_modes_stay_widescreen_and_square_pixel() {
(mode.width, mode.height)
);
}
assert_eq!(
display_size_for_source_mode(EyeSourceMode {
width: 720,
height: 576,
fps: 50,
}),
(1024, 576)
);
assert_eq!(
display_size_for_source_mode(EyeSourceMode {
width: 720,
height: 480,
fps: 60,
}),
(854, 480)
);
}
#[test]

View File

@ -29,6 +29,7 @@ fn contains_idr_handles_short_and_multi_nal_annex_b_streams() {
assert!(contains_idr(&[0, 0, 1, 0x65, 0x00]));
assert!(contains_idr(&[0, 0, 0, 1, 0x41, 0x00, 0, 0, 1, 0x65, 0x00]));
assert!(!contains_idr(&[0, 0, 0, 1, 0x41, 0x00, 0x00]));
assert!(!contains_idr(&[0, 0, 2, 0x65, 0, 0, 0, 2, 0x65]));
}
#[test]