use bssh::config::Config;
use once_cell::sync::Lazy;
use std::env;
use tokio::sync::Mutex;
static ENV_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
#[tokio::test]
async fn test_backendai_env_auto_detection() {
let _guard = ENV_MUTEX.lock().await;
let orig_hosts = env::var("BACKENDAI_CLUSTER_HOSTS").ok();
let orig_host = env::var("BACKENDAI_CLUSTER_HOST").ok();
let orig_role = env::var("BACKENDAI_CLUSTER_ROLE").ok();
unsafe {
env::set_var("BACKENDAI_CLUSTER_HOSTS", "node1.ai,node2.ai,node3.ai");
env::set_var("BACKENDAI_CLUSTER_HOST", "node1.ai");
env::set_var("BACKENDAI_CLUSTER_ROLE", "main");
}
let temp_dir = tempfile::tempdir().unwrap();
let nonexistent_path = temp_dir.path().join("nonexistent.yaml");
let config = Config::load_with_priority(&nonexistent_path)
.await
.expect("Config should load with Backend.AI env");
assert!(config.clusters.contains_key("bai_auto"));
let cluster = config.clusters.get("bai_auto").unwrap();
assert_eq!(
cluster.defaults.ssh_key,
Some("/home/config/ssh/id_cluster".to_string()),
"Backend.AI cluster should use /home/config/ssh/id_cluster as SSH key"
);
assert_eq!(cluster.nodes.len(), 3);
let nodes = config
.resolve_nodes("bai_auto")
.expect("Should resolve bai_auto nodes");
assert_eq!(nodes.len(), 3);
assert_eq!(nodes[0].host, "node1.ai");
assert_eq!(nodes[0].port, 2200); assert_eq!(nodes[1].host, "node2.ai");
assert_eq!(nodes[2].host, "node3.ai");
assert_eq!(
config.get_ssh_key(Some("bai_auto")),
Some("/home/config/ssh/id_cluster".to_string()),
"get_ssh_key should return Backend.AI cluster key path"
);
unsafe {
if let Some(val) = orig_hosts {
env::set_var("BACKENDAI_CLUSTER_HOSTS", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_HOSTS");
}
if let Some(val) = orig_host {
env::set_var("BACKENDAI_CLUSTER_HOST", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_HOST");
}
if let Some(val) = orig_role {
env::set_var("BACKENDAI_CLUSTER_ROLE", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_ROLE");
}
}
}
#[tokio::test]
async fn test_backendai_env_with_single_host() {
let _guard = ENV_MUTEX.lock().await;
let orig_hosts = env::var("BACKENDAI_CLUSTER_HOSTS").ok();
let orig_host = env::var("BACKENDAI_CLUSTER_HOST").ok();
let orig_role = env::var("BACKENDAI_CLUSTER_ROLE").ok();
unsafe {
env::set_var("BACKENDAI_CLUSTER_HOSTS", "single-node.ai");
env::set_var("BACKENDAI_CLUSTER_HOST", "single-node.ai");
env::remove_var("BACKENDAI_CLUSTER_ROLE");
}
let temp_dir = tempfile::tempdir().unwrap();
let nonexistent_path = temp_dir.path().join("nonexistent.yaml");
let config = Config::load_with_priority(&nonexistent_path)
.await
.expect("Config should load");
assert!(config.clusters.contains_key("bai_auto"));
let nodes = config
.resolve_nodes("bai_auto")
.expect("Should resolve nodes");
assert_eq!(nodes.len(), 1);
assert_eq!(nodes[0].host, "single-node.ai");
assert_eq!(nodes[0].port, 2200);
unsafe {
if let Some(val) = orig_hosts {
env::set_var("BACKENDAI_CLUSTER_HOSTS", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_HOSTS");
}
if let Some(val) = orig_host {
env::set_var("BACKENDAI_CLUSTER_HOST", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_HOST");
}
if let Some(val) = orig_role {
env::set_var("BACKENDAI_CLUSTER_ROLE", val);
} else {
env::remove_var("BACKENDAI_CLUSTER_ROLE");
}
}
}
#[tokio::test]
async fn test_no_backendai_env() {
let _guard = ENV_MUTEX.lock().await;
let orig_hosts = env::var("BACKENDAI_CLUSTER_HOSTS").ok();
let orig_host = env::var("BACKENDAI_CLUSTER_HOST").ok();
unsafe {
env::remove_var("BACKENDAI_CLUSTER_HOSTS");
env::remove_var("BACKENDAI_CLUSTER_HOST");
env::remove_var("BACKENDAI_CLUSTER_ROLE");
}
let config = Config::load_with_priority(&std::path::PathBuf::from("nonexistent.yaml"))
.await
.expect("Config should load");
assert!(!config.clusters.contains_key("backendai"));
unsafe {
if let Some(val) = orig_hosts {
env::set_var("BACKENDAI_CLUSTER_HOSTS", val);
}
if let Some(val) = orig_host {
env::set_var("BACKENDAI_CLUSTER_HOST", val);
}
}
}