lesavka/testing/tests/server_camera_runtime_contract.rs

138 lines
3.9 KiB
Rust
Raw Normal View History

//! Integration coverage for the camera runtime activation contract.
//!
//! Scope: validate activation error handling and configuration equality edges
//! through public camera-runtime APIs.
//! Targets: `server/src/camera_runtime.rs`.
//! Why: camera runtime generation and guardrails are core to safe stream
//! transitions, so they need direct integration-level assertions.
use lesavka_server::camera::{CameraCodec, CameraConfig, CameraOutput, HdmiConnector};
use lesavka_server::camera_runtime::{CameraRuntime, camera_cfg_eq};
use serial_test::serial;
use temp_env::with_var;
use tokio::runtime::Runtime;
use tonic::Code;
#[test]
#[serial]
fn activate_rejects_uvc_when_disabled_and_bumps_generation() {
let runtime = CameraRuntime::new();
let cfg = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 1280,
height: 720,
fps: 25,
hdmi: None,
};
with_var("LESAVKA_DISABLE_UVC", Some("1"), || {
let rt = Runtime::new().expect("runtime");
let result = rt.block_on(runtime.activate(&cfg));
match result {
Ok(_) => panic!("UVC should be disabled"),
Err(err) => assert_eq!(err.code(), Code::FailedPrecondition),
}
});
assert!(runtime.is_active(1));
assert!(!runtime.is_active(2));
}
#[test]
#[serial]
fn activate_tracks_latest_generation_across_repeated_failures() {
let runtime = CameraRuntime::new();
let cfg = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 640,
height: 360,
fps: 30,
hdmi: None,
};
with_var("LESAVKA_DISABLE_UVC", Some("1"), || {
let rt = Runtime::new().expect("runtime");
for expected in [1_u64, 2_u64, 3_u64] {
let result = rt.block_on(runtime.activate(&cfg));
match result {
Ok(_) => panic!("UVC should remain disabled"),
Err(err) => assert_eq!(err.code(), Code::FailedPrecondition),
}
assert!(runtime.is_active(expected));
assert!(!runtime.is_active(expected + 1));
}
});
}
#[test]
fn camera_cfg_eq_handles_none_and_hdmi_connector_edges() {
let uvc_a = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 640,
height: 360,
fps: 30,
hdmi: None,
};
let uvc_b = uvc_a.clone();
assert!(camera_cfg_eq(&uvc_a, &uvc_b));
let hdmi_a = CameraConfig {
output: CameraOutput::Hdmi,
codec: CameraCodec::H264,
width: 1920,
height: 1080,
fps: 30,
hdmi: Some(HdmiConnector {
name: String::from("HDMI-A-1"),
id: Some(7),
}),
};
let hdmi_b = hdmi_a.clone();
assert!(camera_cfg_eq(&hdmi_a, &hdmi_b));
let mut different_id = hdmi_a.clone();
different_id.hdmi = Some(HdmiConnector {
name: String::from("HDMI-A-1"),
id: Some(8),
});
assert!(!camera_cfg_eq(&hdmi_a, &different_id));
let mut missing_connector = hdmi_a;
missing_connector.hdmi = None;
assert!(!camera_cfg_eq(&missing_connector, &hdmi_b));
}
#[test]
fn camera_cfg_eq_rejects_output_codec_resolution_and_fps_changes() {
let base = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 1280,
height: 720,
fps: 25,
hdmi: None,
};
let mut changed = base.clone();
changed.output = CameraOutput::Hdmi;
assert!(!camera_cfg_eq(&base, &changed));
changed = base.clone();
changed.codec = CameraCodec::H264;
assert!(!camera_cfg_eq(&base, &changed));
changed = base.clone();
changed.width = 1920;
assert!(!camera_cfg_eq(&base, &changed));
changed = base.clone();
changed.height = 1080;
assert!(!camera_cfg_eq(&base, &changed));
changed = base.clone();
changed.fps = 30;
assert!(!camera_cfg_eq(&base, &changed));
}