lesavka/server/src/tests/camera.rs

294 lines
9.0 KiB
Rust

use super::selection::{parse_hdmi_mode, parse_hdmi_modes, preferred_hdmi_mode};
use super::{
CameraCodec, CameraConfig, CameraOutput, HdmiConnector, HdmiMode, current_camera_config,
update_camera_config,
};
use serial_test::serial;
use std::fs;
use temp_env::with_var;
#[test]
#[serial]
fn camera_config_env_override_prefers_uvc_values() {
with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || {
with_var("LESAVKA_UVC_WIDTH", Some("800"), || {
with_var("LESAVKA_UVC_HEIGHT", Some("600"), || {
with_var("LESAVKA_UVC_FPS", Some("24"), || {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Uvc);
assert_eq!(cfg.codec, CameraCodec::Hevc);
assert_eq!(cfg.width, 800);
assert_eq!(cfg.height, 600);
assert_eq!(cfg.fps, 24);
let cached = current_camera_config();
assert_eq!(cached.output, CameraOutput::Uvc);
assert_eq!(cached.codec, CameraCodec::Hevc);
assert_eq!(cached.width, 800);
assert_eq!(cached.height, 600);
assert_eq!(cached.fps, 24);
});
});
});
});
}
#[test]
#[cfg(not(coverage))]
#[serial]
fn uvc_camera_profile_honors_live_attached_descriptor() {
let temp = tempfile::tempdir().expect("temp configfs dir");
let frame_dir = temp.path().join("streaming/mjpeg/m/720p");
fs::create_dir_all(&frame_dir).expect("mock UVC frame descriptor");
fs::write(frame_dir.join("wWidth"), "640\n").expect("width");
fs::write(frame_dir.join("wHeight"), "480\n").expect("height");
fs::write(frame_dir.join("dwDefaultFrameInterval"), "500000\n").expect("interval");
let configfs_base = temp.path().to_string_lossy().into_owned();
temp_env::with_vars(
[
("LESAVKA_CAM_OUTPUT", Some("uvc")),
("LESAVKA_UVC_WIDTH", Some("1280")),
("LESAVKA_UVC_HEIGHT", Some("720")),
("LESAVKA_UVC_FPS", Some("30")),
("LESAVKA_UVC_INTERVAL", None),
("LESAVKA_UVC_CONFIGFS_BASE", Some(configfs_base.as_str())),
],
|| {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Uvc);
assert_eq!(cfg.codec, CameraCodec::Hevc);
assert_eq!((cfg.width, cfg.height, cfg.fps), (640, 480, 20));
},
);
}
#[test]
#[serial]
fn camera_config_env_override_ignores_uvc_descriptor_codec_for_uplink() {
temp_env::with_vars(
[
("LESAVKA_CAM_OUTPUT", Some("uvc")),
("LESAVKA_UVC_CODEC", Some("h264")),
("LESAVKA_CAM_CODEC", None),
("LESAVKA_UPLINK_CAMERA_CODEC", None),
],
|| {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Uvc);
assert_eq!(cfg.codec, CameraCodec::Hevc);
},
);
}
#[test]
#[serial]
fn camera_config_env_override_honors_explicit_uplink_codec() {
temp_env::with_vars(
[
("LESAVKA_CAM_OUTPUT", Some("uvc")),
("LESAVKA_CAM_CODEC", Some("mjpeg")),
("LESAVKA_UPLINK_CAMERA_CODEC", Some("h265")),
],
|| {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Uvc);
assert_eq!(cfg.codec, CameraCodec::Hevc);
},
);
}
#[test]
#[serial]
fn hdmi_camera_profile_honors_installed_1080p_override() {
with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
with_var("LESAVKA_CAM_CODEC", Some("h264"), || {
with_var("LESAVKA_CAM_WIDTH", Some("1920"), || {
with_var("LESAVKA_CAM_HEIGHT", Some("1080"), || {
with_var("LESAVKA_CAM_FPS", Some("30"), || {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Hdmi);
assert_eq!(cfg.codec, CameraCodec::H264);
assert_eq!(cfg.width, 1920);
assert_eq!(cfg.height, 1080);
assert_eq!(cfg.fps, 30);
});
});
});
});
});
}
#[test]
#[serial]
fn hdmi_camera_profile_prefers_mjpeg_without_hardware_decoder() {
with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
with_var("LESAVKA_HW_H264", None::<&str>, || {
with_var("LESAVKA_CAM_CODEC", None::<&str>, || {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Hdmi);
assert_eq!(cfg.codec, CameraCodec::Mjpeg);
assert_eq!(cfg.width, 1280);
assert_eq!(cfg.height, 720);
assert_eq!(cfg.fps, 30);
});
});
});
}
#[test]
#[serial]
fn hdmi_camera_profile_honors_explicit_codec_override() {
with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
with_var("LESAVKA_HW_H264", None::<&str>, || {
with_var("LESAVKA_CAM_CODEC", Some("h264"), || {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Hdmi);
assert_eq!(cfg.codec, CameraCodec::H264);
});
});
});
}
#[test]
fn hdmi_mode_parsing_accepts_sysfs_and_override_shapes() {
assert_eq!(
parse_hdmi_mode("1920x1080"),
Some(HdmiMode {
width: 1920,
height: 1080,
})
);
assert_eq!(
parse_hdmi_mode("1280x720p60"),
Some(HdmiMode {
width: 1280,
height: 720,
})
);
assert_eq!(parse_hdmi_mode("not-a-mode"), None);
let modes = parse_hdmi_modes("1920x1080\n1024x768,800x600\n");
assert_eq!(modes.len(), 3);
assert_eq!(modes[0].width, 1920);
assert_eq!(modes[2].height, 600);
}
#[test]
fn preferred_hdmi_mode_chooses_standard_capture_adapter_mode() {
let modes = parse_hdmi_modes("1024x768\n1920x1080\n800x600\n");
assert_eq!(
preferred_hdmi_mode(&modes),
Some(HdmiMode {
width: 1920,
height: 1080,
})
);
let modes = parse_hdmi_modes("1600x900\n1024x768\n");
assert_eq!(
preferred_hdmi_mode(&modes),
Some(HdmiMode {
width: 1600,
height: 900,
})
);
let modes = parse_hdmi_modes("1024x768\n800x600\n");
assert_eq!(
preferred_hdmi_mode(&modes),
Some(HdmiMode {
width: 1024,
height: 768,
})
);
}
#[test]
#[serial]
fn hdmi_display_size_uses_adapter_mode_without_changing_uplink_profile() {
let cfg = CameraConfig {
output: CameraOutput::Hdmi,
codec: CameraCodec::H264,
width: 1280,
height: 720,
fps: 30,
hdmi: Some(HdmiConnector {
name: String::from("card1-HDMI-A-2"),
id: Some(43),
modes: parse_hdmi_modes("1920x1080\n1024x768\n800x600\n"),
}),
};
with_var("LESAVKA_HDMI_WIDTH", None::<&str>, || {
with_var("LESAVKA_HDMI_HEIGHT", None::<&str>, || {
assert_eq!((cfg.width, cfg.height), (1280, 720));
assert_eq!(cfg.hdmi_display_size(), (1920, 1080));
});
});
}
#[test]
#[serial]
fn hdmi_display_size_honors_explicit_local_override() {
let cfg = CameraConfig {
output: CameraOutput::Hdmi,
codec: CameraCodec::H264,
width: 1280,
height: 720,
fps: 30,
hdmi: Some(HdmiConnector {
name: String::from("card1-HDMI-A-2"),
id: Some(43),
modes: parse_hdmi_modes("1920x1080\n"),
}),
};
with_var("LESAVKA_HDMI_WIDTH", Some("1024"), || {
with_var("LESAVKA_HDMI_HEIGHT", Some("768"), || {
assert_eq!(cfg.hdmi_display_size(), (1024, 768));
});
});
}
#[test]
fn non_hdmi_display_size_uses_camera_profile() {
let cfg = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 800,
height: 600,
fps: 25,
hdmi: None,
};
assert_eq!(cfg.hdmi_display_size(), (800, 600));
}
#[test]
#[cfg(coverage)]
#[serial]
fn coverage_hdmi_connector_env_sets_adapter_display_mode() {
temp_env::with_vars(
[
("LESAVKA_CAM_OUTPUT", Some("hdmi")),
("LESAVKA_CAM_WIDTH", Some("1280")),
("LESAVKA_CAM_HEIGHT", Some("720")),
("LESAVKA_CAM_FPS", Some("30")),
("LESAVKA_HDMI_CONNECTOR", Some("card1-HDMI-A-2")),
("LESAVKA_HDMI_MODES", Some("1920x1080,1280x720")),
("LESAVKA_HDMI_WIDTH", None),
("LESAVKA_HDMI_HEIGHT", None),
],
|| {
let cfg = update_camera_config();
assert_eq!(cfg.output, CameraOutput::Hdmi);
assert_eq!((cfg.width, cfg.height, cfg.fps), (1280, 720, 30));
let hdmi = cfg.hdmi.as_ref().expect("HDMI connector from env");
assert_eq!(hdmi.name, "card1-HDMI-A-2");
assert_eq!(hdmi.id, None);
assert_eq!(cfg.hdmi_display_size(), (1920, 1080));
},
);
}