252 lines
8.4 KiB
Rust
252 lines
8.4 KiB
Rust
//! Include-based coverage for server camera sink internals.
|
|
//!
|
|
//! Scope: include `server/src/video_sinks.rs` and directly exercise private sink
|
|
//! selection/dispatch helpers through stable constructor paths.
|
|
//! Targets: `server/src/video_sinks.rs`.
|
|
//! Why: sink internals carry substantial branch logic beyond public smoke tests.
|
|
|
|
mod camera {
|
|
pub use lesavka_server::camera::*;
|
|
}
|
|
|
|
mod video_support {
|
|
pub use lesavka_server::video_support::*;
|
|
}
|
|
|
|
#[allow(warnings)]
|
|
mod video_sinks_include_contract {
|
|
include!(env!("LESAVKA_SERVER_VIDEO_SINKS_SRC"));
|
|
|
|
use crate::camera::{CameraOutput, HdmiConnector, HdmiMode};
|
|
use serial_test::serial;
|
|
use temp_env::with_var;
|
|
|
|
fn cfg(codec: CameraCodec) -> CameraConfig {
|
|
CameraConfig {
|
|
output: CameraOutput::Hdmi,
|
|
codec,
|
|
width: 640,
|
|
height: 360,
|
|
fps: 24,
|
|
hdmi: None,
|
|
}
|
|
}
|
|
|
|
fn hdmi_cfg_with_ugreen_like_modes(codec: CameraCodec) -> CameraConfig {
|
|
CameraConfig {
|
|
output: CameraOutput::Hdmi,
|
|
codec,
|
|
width: 1280,
|
|
height: 720,
|
|
fps: 30,
|
|
hdmi: Some(HdmiConnector {
|
|
name: String::from("card1-HDMI-A-2"),
|
|
id: Some(43),
|
|
modes: vec![
|
|
HdmiMode {
|
|
width: 1920,
|
|
height: 1080,
|
|
},
|
|
HdmiMode {
|
|
width: 1024,
|
|
height: 768,
|
|
},
|
|
],
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn init_gst() {
|
|
let _ = gst::init();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn build_hdmi_sink_respects_env_override_success_path() {
|
|
init_gst();
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
let sink = build_hdmi_sink(&cfg(CameraCodec::H264));
|
|
assert!(sink.is_ok(), "known override sink should build");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[cfg(not(coverage))]
|
|
fn build_hdmi_sink_configures_fbdev_override_for_capture_adapters() {
|
|
init_gst();
|
|
if gst::ElementFactory::find("fbdevsink").is_none() {
|
|
return;
|
|
}
|
|
|
|
with_var("LESAVKA_HDMI_SINK", Some("fbdevsink"), || {
|
|
with_var("LESAVKA_HDMI_FBDEV", Some("/dev/fb42"), || {
|
|
let sink = build_hdmi_sink(&cfg(CameraCodec::H264))
|
|
.expect("fbdevsink override should build");
|
|
|
|
if sink.has_property("device", None) {
|
|
assert_eq!(sink.property::<String>("device"), "/dev/fb42");
|
|
}
|
|
if sink.has_property("sync", None) {
|
|
assert!(
|
|
!sink.property::<bool>("sync"),
|
|
"fbdev HDMI output should not clock-sync WAN camera frames"
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn build_hdmi_sink_invalid_override_surfaces_error() {
|
|
init_gst();
|
|
with_var(
|
|
"LESAVKA_HDMI_SINK",
|
|
Some("definitely-not-a-real-gst-element"),
|
|
|| {
|
|
let sink = build_hdmi_sink(&cfg(CameraCodec::H264));
|
|
assert!(sink.is_err(), "invalid override must fail");
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn build_hdmi_sink_falls_back_when_override_is_unset() {
|
|
init_gst();
|
|
with_var("LESAVKA_HDMI_SINK", None::<&str>, || {
|
|
let sink = build_hdmi_sink(&cfg(CameraCodec::H264));
|
|
assert!(sink.is_ok(), "fallback sink should build");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn hdmi_display_size_scales_uplink_to_capture_adapter_mode() {
|
|
let cfg = hdmi_cfg_with_ugreen_like_modes(CameraCodec::H264);
|
|
assert_eq!((cfg.width, cfg.height), (1280, 720));
|
|
assert_eq!(cfg.hdmi_display_size(), (1920, 1080));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[cfg(not(coverage))]
|
|
fn build_hdmi_sink_pins_kms_connector_and_modesetting_when_available() {
|
|
init_gst();
|
|
if gst::ElementFactory::find("kmssink").is_none() {
|
|
return;
|
|
}
|
|
|
|
with_var("LESAVKA_HDMI_SINK", None::<&str>, || {
|
|
with_var("LESAVKA_HDMI_DRIVER", Some("vc4"), || {
|
|
with_var("LESAVKA_HDMI_RESTORE_CRTC", None::<&str>, || {
|
|
let sink = build_hdmi_sink(&hdmi_cfg_with_ugreen_like_modes(CameraCodec::H264))
|
|
.expect("kmssink should build");
|
|
|
|
if sink.has_property("force-modesetting", None) {
|
|
assert!(
|
|
sink.property::<bool>("force-modesetting"),
|
|
"kmssink must drive the HDMI mode instead of relying on desktop state"
|
|
);
|
|
}
|
|
if sink.has_property("restore-crtc", None) {
|
|
assert!(
|
|
!sink.property::<bool>("restore-crtc"),
|
|
"dedicated HDMI capture output should not restore the console CRTC"
|
|
);
|
|
}
|
|
if sink.has_property("connector-id", None) {
|
|
assert_eq!(sink.property::<i32>("connector-id"), 43);
|
|
}
|
|
if sink.has_property("driver-name", None) {
|
|
assert_eq!(sink.property::<String>("driver-name"), "vc4");
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn bool_env_parser_accepts_operator_friendly_values() {
|
|
with_var("LESAVKA_BOOL_TEST", None::<&str>, || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), None);
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("yes"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(true));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("TRUE"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(true));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("1"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(true));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("on"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(true));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("off"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(false));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("0"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(false));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("false"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(false));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("no"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), Some(false));
|
|
});
|
|
with_var("LESAVKA_BOOL_TEST", Some("shrug"), || {
|
|
assert_eq!(read_bool_env("LESAVKA_BOOL_TEST"), None);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn camera_sink_dispatch_is_stable_for_hdmi_variant() {
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
if let Ok(sink) = HdmiSink::new(&cfg(CameraCodec::Mjpeg)) {
|
|
let cam_sink = CameraSink::Hdmi(sink);
|
|
cam_sink.push(VideoPacket {
|
|
id: 8,
|
|
pts: 1,
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
..Default::default()
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn camera_sink_dispatch_is_stable_for_uvc_variant() {
|
|
if let Ok(sink) = WebcamSink::new("/dev/video-definitely-missing", &cfg(CameraCodec::Mjpeg))
|
|
{
|
|
let cam_sink = CameraSink::Uvc(sink);
|
|
cam_sink.push(VideoPacket {
|
|
id: 9,
|
|
pts: 2,
|
|
data: vec![0xFF, 0xD8, 0xFF, 0xD9],
|
|
..Default::default()
|
|
});
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn camera_relay_feed_covers_dev_mode_dump_branch_without_panicking() {
|
|
with_var("LESAVKA_DEV_MODE", Some("1"), || {
|
|
with_var("LESAVKA_HDMI_SINK", Some("autovideosink"), || {
|
|
if let Ok(relay) = CameraRelay::new_hdmi(3, &cfg(CameraCodec::H264)) {
|
|
relay.feed(VideoPacket {
|
|
id: 3,
|
|
pts: 3,
|
|
data: vec![0, 0, 0, 1, 0x65, 0x88, 0x84],
|
|
..Default::default()
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|