lesavka/tests/unit/client/uplink/client_upstream_keyframe_state_unit.rs

92 lines
2.8 KiB
Rust

// Unit coverage for HEVC recovery state in the client upstream path.
//
// Scope: include the client HEVC keyframe helpers with a tiny camera-config
// shim so the logic can be tested without GTK/GStreamer capture hardware.
// Targets: `client/src/app/uplink_media/video_keyframes.rs`.
// Why: freshness-first dropping is only safe for predictive codecs when the
// next emitted video frame is a clean recovery point.
mod input {
pub mod camera {
#[derive(Clone, Copy)]
pub enum CameraCodec {
Mjpeg,
Hevc,
}
#[derive(Clone, Copy)]
pub struct CameraConfig {
pub codec: CameraCodec,
}
}
}
use lesavka_common::lesavka::{UpstreamMediaBundle, VideoPacket};
use temp_env::with_vars;
include!("../../../../client/src/app/uplink_media/video_keyframes.rs");
fn video_bundle(data: Vec<u8>) -> UpstreamMediaBundle {
UpstreamMediaBundle {
video: Some(VideoPacket {
data,
..Default::default()
}),
..Default::default()
}
}
#[test]
fn annex_b_irap_detection_handles_three_and_four_byte_start_codes() {
assert!(contains_hevc_irap(&[0, 0, 0, 1, 0x26, 0x01, 0xaa]));
assert!(contains_hevc_irap(&[0, 0, 1, 0x28, 0x01, 0xbb]));
assert!(contains_hevc_irap(&[
0, 0, 1, 0x02, 0x01, 0xcc, 0, 0, 0, 1, 0x2e, 0x01, 0xdd
]));
assert!(!contains_hevc_irap(&[0, 0, 0, 1, 0x02, 0x01, 0xee]));
assert!(!contains_hevc_irap(&[0x26, 0x01, 0xaa]));
}
#[test]
fn recovery_wait_holds_delta_bundles_and_releases_on_irap() {
let delta = video_bundle(vec![0, 0, 0, 1, 0x02, 0x01, 0xaa]);
let irap = video_bundle(vec![0, 0, 0, 1, 0x26, 0x01, 0xbb]);
assert!(!should_hold_hevc_bundle_for_keyframe_recovery(
false, &delta
));
assert!(should_hold_hevc_bundle_for_keyframe_recovery(true, &delta));
assert!(!should_hold_hevc_bundle_for_keyframe_recovery(true, &irap));
assert!(bundle_has_hevc_recovery_keyframe(&irap));
assert!(!bundle_has_hevc_recovery_keyframe(&delta));
}
#[test]
fn capture_gap_only_enters_wait_state_when_hevc_recovery_applies() {
let mut waiting = false;
note_hevc_capture_gap(false, &mut waiting);
assert!(!waiting);
note_hevc_capture_gap(true, &mut waiting);
assert!(waiting);
}
#[test]
fn codec_selection_enables_recovery_for_hevc_only() {
use input::camera::{CameraCodec, CameraConfig};
assert!(upstream_camera_uses_hevc(Some(CameraConfig {
codec: CameraCodec::Hevc,
})));
assert!(!upstream_camera_uses_hevc(Some(CameraConfig {
codec: CameraCodec::Mjpeg,
})));
with_vars([("LESAVKA_CAM_CODEC", Some("h.265"))], || {
assert!(upstream_camera_uses_hevc(None));
});
with_vars([("LESAVKA_CAM_CODEC", Some("mjpeg"))], || {
assert!(!upstream_camera_uses_hevc(None));
});
}