#![allow(clippy::too_many_arguments)]
use rstest::rstest;
use serial_test::serial;
use std::env;
use torc::client::commands::slurm::create_node_resources;
use torc::client::hpc::slurm_interface::SlurmInterface;
fn setup_slurm_env(
cpus_on_node: &str,
mem_per_node: &str,
num_nodes: &str,
cpus_per_task: &str,
job_gpus: Option<&str>,
) {
unsafe {
env::set_var("USER", "testuser");
env::set_var("SLURM_CPUS_ON_NODE", cpus_on_node);
env::set_var("SLURM_MEM_PER_NODE", mem_per_node);
env::set_var("SLURM_JOB_NUM_NODES", num_nodes);
env::set_var("SLURM_CPUS_PER_TASK", cpus_per_task);
if let Some(gpus) = job_gpus {
env::set_var("SLURM_JOB_GPUS", gpus);
}
}
}
fn cleanup_slurm_env(preserve_user: bool, original_user: Option<String>) {
unsafe {
if preserve_user {
if let Some(user) = original_user {
env::set_var("USER", user);
} else {
env::remove_var("USER");
}
} else {
env::remove_var("USER");
}
env::remove_var("SLURM_CPUS_ON_NODE");
env::remove_var("SLURM_MEM_PER_NODE");
env::remove_var("SLURM_JOB_NUM_NODES");
env::remove_var("SLURM_CPUS_PER_TASK");
env::remove_var("SLURM_JOB_GPUS");
}
}
#[rstest]
#[case(16, "32768", 2, 4, Some("0,1"), 123, false, 16, 32.0, 2, 2)] #[case(16, "16384", 1, 4, None, 456, true, 4, 4.0, 0, 1)] #[case(32, "65536", 4, 8, Some("0,1,2,3"), 789, false, 32, 64.0, 4, 4)] #[case(8, "8192", 1, 2, Some("0"), 101, true, 2, 2.0, 1, 1)] #[serial(node_resources)]
fn test_create_node_resources(
#[case] cpus_on_node: usize,
#[case] mem_per_node: &str,
#[case] num_nodes: usize,
#[case] cpus_per_task: usize,
#[case] job_gpus: Option<&str>,
#[case] scheduler_config_id: i64,
#[case] is_subtask: bool,
#[case] expected_cpus: i64,
#[case] expected_memory: f64,
#[case] expected_gpus: i64,
#[case] expected_nodes: i64,
) {
let original_user = env::var("USER").ok();
setup_slurm_env(
&cpus_on_node.to_string(),
mem_per_node,
&num_nodes.to_string(),
&cpus_per_task.to_string(),
job_gpus,
);
let interface = SlurmInterface::new().expect("Failed to create SlurmInterface");
let resources = create_node_resources(&interface, Some(scheduler_config_id), is_subtask);
assert_eq!(resources.num_cpus, expected_cpus, "CPU count mismatch");
assert_eq!(
resources.memory_gb, expected_memory,
"Memory amount mismatch"
);
assert_eq!(resources.num_gpus, expected_gpus, "GPU count mismatch");
assert_eq!(resources.num_nodes, expected_nodes, "Node count mismatch");
assert_eq!(
resources.scheduler_config_id,
Some(scheduler_config_id),
"Scheduler config ID mismatch"
);
cleanup_slurm_env(true, original_user);
}
#[rstest]
#[serial(node_resources)]
fn test_create_node_resources_zero_values() {
let original_user = env::var("USER").ok();
setup_slurm_env("0", "0", "0", "0", Some(""));
let interface = SlurmInterface::new().expect("Failed to create SlurmInterface");
let resources = create_node_resources(&interface, Some(999), false);
assert_eq!(
resources.num_cpus, 0,
"CPU count should be 0 (per-node value)"
);
assert_eq!(
resources.memory_gb, 0.0,
"Memory should be 0 (per-node value)"
);
assert_eq!(
resources.num_gpus, 1,
"GPU count should be 1 (per-node value from empty SLURM_JOB_GPUS)"
);
assert_eq!(resources.num_nodes, 0, "Node count should be 0");
assert_eq!(
resources.scheduler_config_id,
Some(999),
"Scheduler config ID should be set"
);
cleanup_slurm_env(true, original_user);
}
#[rstest]
#[serial(node_resources)]
fn test_create_node_resources_gpu_parsing() {
let original_user = env::var("USER").ok();
let test_cases = vec![
("0", 1), ("0,1", 2), ("0,1,2,3", 4), ("", 1), ];
for (gpu_string, expected_count) in test_cases {
setup_slurm_env("8", "8192", "1", "4", Some(gpu_string));
let interface = SlurmInterface::new().expect("Failed to create SlurmInterface");
let resources = create_node_resources(&interface, Some(123), false);
assert_eq!(
resources.num_gpus, expected_count,
"GPU count mismatch for '{}'",
gpu_string
);
cleanup_slurm_env(false, None);
}
cleanup_slurm_env(true, original_user);
}