test: cover mjpeg normalizer memory regression
This commit is contained in:
parent
0c8d4732ae
commit
3337ceac61
@ -561,6 +561,10 @@ path = "tests/regression/server/gadget/server_gadget_recovery_contract.rs"
|
||||
name = "server_main_usb_recovery_contract"
|
||||
path = "tests/regression/server/main/server_main_usb_recovery_contract.rs"
|
||||
|
||||
[[test]]
|
||||
name = "server_mjpeg_normalizer_memory_regression"
|
||||
path = "tests/regression/server/video_sinks/server_mjpeg_normalizer_memory_regression.rs"
|
||||
|
||||
[[test]]
|
||||
name = "client_log_noise_contract"
|
||||
path = "tests/reliability/client/diagnostics/client_log_noise_contract.rs"
|
||||
|
||||
@ -128,6 +128,10 @@ fn corrupt_video_and_codec_modes_have_guard_compatibility_and_chaos_evidence() {
|
||||
category: "chaos",
|
||||
path: "tests/chaos/server/video_sinks/hevc_mjpeg_guard_chaos_contract.rs",
|
||||
},
|
||||
EvidencePath {
|
||||
category: "regression",
|
||||
path: "tests/regression/server/video_sinks/server_mjpeg_normalizer_memory_regression.rs",
|
||||
},
|
||||
EvidencePath {
|
||||
category: "performance",
|
||||
path: "tests/performance/server/video_sinks/hevc_mjpeg_handoff_performance_contract.rs",
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
// Regression coverage for the direct-MJPEG normalizer RSS leak.
|
||||
//
|
||||
// Scope: lock down the safe production defaults and lifecycle cleanup for the
|
||||
// server UVC MJPEG path.
|
||||
// Targets: server/src/video_sinks/hevc_mjpeg_guard.rs,
|
||||
// server/src/video_sinks/webcam_sink.rs, server/src/camera_runtime.rs, and
|
||||
// the camera/upstream media RPC lifecycles.
|
||||
// Why: the native GStreamer jpegdec/jpegenc normalizer can retain process RSS
|
||||
// during long calls; future changes must keep it opt-in, guarded, and cleaned
|
||||
// up when the client stream closes.
|
||||
|
||||
mod video_support {
|
||||
pub fn env_u32(name: &str, default: u32) -> u32 {
|
||||
std::env::var(name)
|
||||
.ok()
|
||||
.and_then(|value| value.trim().parse().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::items_after_test_module)]
|
||||
mod guard {
|
||||
include!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/server/src/video_sinks/hevc_mjpeg_guard.rs"
|
||||
));
|
||||
|
||||
pub fn normalizer_enabled() -> bool {
|
||||
direct_mjpeg_normalize_enabled()
|
||||
}
|
||||
|
||||
pub fn normalizer_rss_limit_kb() -> Option<u64> {
|
||||
direct_mjpeg_normalize_rss_limit_kb()
|
||||
}
|
||||
}
|
||||
|
||||
const SERVER_INSTALL: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/scripts/install/server.sh"
|
||||
));
|
||||
const WEBCAM_SINK: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/server/src/video_sinks/webcam_sink.rs"
|
||||
));
|
||||
const CAMERA_RUNTIME: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/server/src/camera_runtime.rs"
|
||||
));
|
||||
const CAMERA_RPC: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/server/src/main/relay_service/camera_stream_rpc.rs"
|
||||
));
|
||||
const UPSTREAM_MEDIA_RPC: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/server/src/main/relay_service/upstream_media_rpc.rs"
|
||||
));
|
||||
|
||||
fn assert_ordered(haystack: &str, earlier: &str, later: &str) {
|
||||
let earlier_pos = haystack
|
||||
.find(earlier)
|
||||
.unwrap_or_else(|| panic!("missing earlier marker {earlier:?}"));
|
||||
let later_pos = haystack
|
||||
.find(later)
|
||||
.unwrap_or_else(|| panic!("missing later marker {later:?}"));
|
||||
assert!(
|
||||
earlier_pos < later_pos,
|
||||
"expected marker {earlier:?} before {later:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_mjpeg_normalizer_is_opt_in_after_native_rss_leak() {
|
||||
temp_env::with_vars(
|
||||
[
|
||||
("LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE", None::<&str>),
|
||||
(
|
||||
"LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_RSS_LIMIT_MB",
|
||||
None::<&str>,
|
||||
),
|
||||
],
|
||||
|| {
|
||||
assert!(
|
||||
!guard::normalizer_enabled(),
|
||||
"direct MJPEG normalization must stay opt-in after the native RSS leak"
|
||||
);
|
||||
assert_eq!(guard::normalizer_rss_limit_kb(), Some(768 * 1024));
|
||||
},
|
||||
);
|
||||
|
||||
temp_env::with_vars(
|
||||
[
|
||||
("LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE", Some("on")),
|
||||
("LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_RSS_LIMIT_MB", Some("0")),
|
||||
],
|
||||
|| {
|
||||
assert!(guard::normalizer_enabled());
|
||||
assert_eq!(guard::normalizer_rss_limit_kb(), None);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn installer_keeps_the_leaking_native_normalizer_disabled_by_default() {
|
||||
assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE:-0}"));
|
||||
assert!(!SERVER_INSTALL.contains("${LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE:-1}"));
|
||||
assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_RSS_LIMIT_MB:-768}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opt_in_normalizer_has_rss_fuse_before_per_frame_gstreamer_allocation() {
|
||||
assert!(WEBCAM_SINK.contains("current_process_rss_kb"));
|
||||
assert!(WEBCAM_SINK.contains("direct_mjpeg_normalize_rss_limit_kb"));
|
||||
assert!(WEBCAM_SINK.contains(
|
||||
"direct MJPEG normalization disabled because server RSS exceeded its safety limit"
|
||||
));
|
||||
assert_ordered(
|
||||
WEBCAM_SINK,
|
||||
"direct_mjpeg_normalize_rss_limit_kb()",
|
||||
"gst::Buffer::from_slice(pkt.data.clone())",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closed_camera_streams_release_native_uvc_pipeline_state() {
|
||||
assert!(CAMERA_RUNTIME.contains("pub async fn release_if_active"));
|
||||
assert!(CAMERA_RUNTIME.contains("slot.take()"));
|
||||
assert!(WEBCAM_SINK.contains("impl Drop for WebcamSink"));
|
||||
assert!(WEBCAM_SINK.contains("set_state(gst::State::Null)"));
|
||||
assert!(CAMERA_RPC.contains("camera_rt.release_if_active(camera_session_id).await"));
|
||||
assert!(UPSTREAM_MEDIA_RPC.contains("camera_rt.release_if_active(camera_session_id).await"));
|
||||
}
|
||||
@ -267,6 +267,10 @@
|
||||
"category": "regression",
|
||||
"new": "tests/regression/server/main/server_main_usb_recovery_contract.rs"
|
||||
},
|
||||
{
|
||||
"category": "regression",
|
||||
"new": "tests/regression/server/video_sinks/server_mjpeg_normalizer_memory_regression.rs"
|
||||
},
|
||||
{
|
||||
"category": "contract",
|
||||
"new": "tests/contract/server/runtime_support/server_runtime_contract.rs"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user