2026-04-12 18:41:13 -03:00
|
|
|
//! Integration smoke coverage for server camera sink constructors.
|
|
|
|
|
//!
|
|
|
|
|
//! Scope: exercise public sink and relay constructors with resilient
|
|
|
|
|
//! assertions that tolerate host-specific media capabilities.
|
|
|
|
|
//! Targets: `server/src/video_sinks.rs`.
|
|
|
|
|
//! Why: sink setup contains substantial branch logic that should be executed
|
|
|
|
|
//! in CI even when real HDMI/UVC hardware is unavailable.
|
|
|
|
|
|
|
|
|
|
use lesavka_common::lesavka::VideoPacket;
|
|
|
|
|
use lesavka_server::camera::{CameraCodec, CameraConfig, CameraOutput};
|
|
|
|
|
use lesavka_server::video::{CameraRelay, HdmiSink, WebcamSink};
|
|
|
|
|
use serial_test::serial;
|
|
|
|
|
use temp_env::with_var;
|
|
|
|
|
|
|
|
|
|
fn hdmi_config(codec: CameraCodec) -> CameraConfig {
|
|
|
|
|
CameraConfig {
|
|
|
|
|
output: CameraOutput::Hdmi,
|
|
|
|
|
codec,
|
|
|
|
|
width: 640,
|
|
|
|
|
height: 360,
|
|
|
|
|
fps: 30,
|
|
|
|
|
hdmi: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn webcam_sink_constructor_is_stable_for_missing_uvc_device() {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::Mjpeg);
|
|
|
|
|
match WebcamSink::new("/dev/video-definitely-missing", &cfg) {
|
|
|
|
|
Ok(sink) => sink.push(VideoPacket {
|
|
|
|
|
id: 2,
|
|
|
|
|
pts: 0,
|
|
|
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn hdmi_sink_constructor_and_push_are_stable_with_override() {
|
|
|
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::H264);
|
|
|
|
|
match HdmiSink::new(&cfg) {
|
|
|
|
|
Ok(sink) => sink.push(VideoPacket {
|
|
|
|
|
id: 2,
|
|
|
|
|
pts: 0,
|
|
|
|
|
data: vec![0, 0, 0, 1, 0x65],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn camera_relay_hdmi_constructor_and_feed_are_stable() {
|
|
|
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::Mjpeg);
|
|
|
|
|
match CameraRelay::new_hdmi(7, &cfg) {
|
|
|
|
|
Ok(relay) => relay.feed(VideoPacket {
|
|
|
|
|
id: 2,
|
|
|
|
|
pts: 123,
|
|
|
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn camera_relay_uvc_constructor_is_stable_for_missing_device() {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::Mjpeg);
|
|
|
|
|
match CameraRelay::new_uvc(9, "/dev/video-definitely-missing", &cfg) {
|
|
|
|
|
Ok(relay) => relay.feed(VideoPacket {
|
|
|
|
|
id: 2,
|
|
|
|
|
pts: 321,
|
|
|
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-13 02:52:32 -03:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn webcam_sink_h264_constructor_path_is_stable() {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::H264);
|
|
|
|
|
match WebcamSink::new("/dev/video-definitely-missing", &cfg) {
|
|
|
|
|
Ok(sink) => sink.push(VideoPacket {
|
|
|
|
|
id: 3,
|
|
|
|
|
pts: 55,
|
|
|
|
|
data: vec![0, 0, 0, 1, 0x65],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn hdmi_sink_mjpeg_constructor_path_is_stable() {
|
|
|
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::Mjpeg);
|
|
|
|
|
match HdmiSink::new(&cfg) {
|
|
|
|
|
Ok(sink) => sink.push(VideoPacket {
|
|
|
|
|
id: 4,
|
|
|
|
|
pts: 99,
|
|
|
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
|
|
|
}),
|
|
|
|
|
Err(err) => assert!(!err.to_string().trim().is_empty()),
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[serial]
|
|
|
|
|
fn hdmi_sink_override_with_invalid_element_returns_error() {
|
|
|
|
|
with_var("LESAVKA_HDMI_SINK", Some("definitely-not-a-real-gst-element"), || {
|
|
|
|
|
let cfg = hdmi_config(CameraCodec::H264);
|
|
|
|
|
let result = HdmiSink::new(&cfg);
|
|
|
|
|
assert!(result.is_err(), "invalid sink override should fail construction");
|
|
|
|
|
});
|
|
|
|
|
}
|