use std::time::Duration;
use super::*;
use crate::runtime::numeric::duration_millis_u64;
fn backend_json(free: u64) -> String {
serde_json::json!({
"devices": [
{
"type": "GPU",
"name": "CUDA0",
"deviceId": "0000:01:00.0",
"memoryFreeBytes": free
},
{
"type": "CPU",
"name": "CPU",
"memoryFreeBytes": 1
}
]
})
.to_string()
}
fn test_lease_root(name: &str) -> PathBuf {
let root = std::env::temp_dir().join(format!(
"sipp-rs-residency-test-{}-{}",
name,
std::process::id()
));
let _ = fs::remove_dir_all(&root);
root
}
#[test]
fn gpu_runtime_acquires_and_releases_lease() {
let root = test_lease_root("release");
let config = NativeRuntimeConfig::default();
let lease = acquire_residency_lease_in(&config, &backend_json(u64::MAX), &root).expect("lease");
assert_eq!(lease.as_ref().map(ResidencyLease::len), Some(1));
assert_eq!(fs::read_dir(&root).expect("lease dir").count(), 1);
drop(lease);
assert_eq!(fs::read_dir(&root).expect("lease dir").count(), 0);
let _ = fs::remove_dir_all(root);
}
#[test]
fn gpu_runtime_rejects_when_lease_slots_are_full() {
let root = test_lease_root("full");
let config = NativeRuntimeConfig::default();
let first = acquire_residency_lease_in(&config, &backend_json(u64::MAX), &root).expect("lease");
assert!(first.is_some());
let error = acquire_residency_lease_in(&config, &backend_json(u64::MAX), &root)
.expect_err("second lease should fail");
assert!(matches!(error, Error::RuntimeCommand(message) if message.contains("already has")));
drop(first);
let _ = fs::remove_dir_all(root);
}
#[test]
fn stale_lease_file_is_removed_and_reused() {
let root = test_lease_root("stale");
let config = NativeRuntimeConfig::default();
fs::create_dir_all(&root).expect("lease dir");
let path = root.join("gpu-0000_01_00_0-slot-0.lock");
let stale_pid = u32::MAX;
fs::write(
&path,
serde_json::json!({
"pid": stale_pid,
"device": "0000_01_00_0",
"slot": 0,
"createdAtUnixMs": 1,
})
.to_string(),
)
.expect("stale lease");
let lease = acquire_residency_lease_in(&config, &backend_json(u64::MAX), &root).expect("lease");
assert_eq!(lease.as_ref().map(ResidencyLease::len), Some(1));
let payload = fs::read_to_string(&path).expect("new lease payload");
let value: Value = serde_json::from_str(&payload).expect("lease json");
assert_eq!(
value.get("pid").and_then(Value::as_u64),
Some(u64::from(std::process::id()))
);
drop(lease);
let _ = fs::remove_dir_all(root);
}
#[test]
fn cpu_runtime_skips_gpu_lease() {
let root = test_lease_root("cpu");
let mut config = NativeRuntimeConfig::default();
config.placement.gpu_layers = GpuLayerConfig::Count(0);
let lease = acquire_residency_lease_in(&config, &backend_json(u64::MAX), &root).expect("lease");
assert!(lease.is_none());
assert!(!root.exists());
}
#[test]
fn duration_millis_saturates_at_u64_max() {
let oversized = Duration::from_millis(u64::MAX).saturating_add(Duration::from_millis(1));
assert_eq!(duration_millis_u64(oversized), u64::MAX);
}
#[test]
fn vram_margin_rejects_too_little_free_memory() {
let root = test_lease_root("margin");
let mut config = NativeRuntimeConfig::default();
config.residency.gpu_memory_safety_margin_bytes = 128;
let error = acquire_residency_lease_in(&config, &backend_json(127), &root)
.expect_err("margin should reject");
assert!(matches!(error, Error::RuntimeCommand(message) if message.contains("safety margin")));
let _ = fs::remove_dir_all(root);
}
#[cfg(unix)]
#[test]
fn oversized_pid_is_not_treated_as_running_on_unix() {
assert!(!process_is_running(u32::MAX));
}