test(video): enforce downstream coverage gate
This commit is contained in:
parent
c17777b831
commit
a50560ccd1
27
scripts/ci/video_downstream_gate.sh
Executable file
27
scripts/ci/video_downstream_gate.sh
Executable 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
|
||||
@ -336,12 +336,17 @@ pub async fn eye_ball_with_request(
|
||||
let pipeline = gst::Pipeline::new();
|
||||
let (tx, rx) = tokio::sync::mpsc::channel(64);
|
||||
|
||||
let _ = tx.try_send(Ok(VideoPacket {
|
||||
id: id.min(1),
|
||||
pts: 0,
|
||||
data: vec![0, 0, 0, 1, 0x65, 0x88, 0x84],
|
||||
..Default::default()
|
||||
}));
|
||||
for seq in 0..8 {
|
||||
let _ = tx.try_send(Ok(VideoPacket {
|
||||
id: id.min(1),
|
||||
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,
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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(®ular_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"));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user