use std::path::{Path, PathBuf};
use super::types::{Config, InteractiveMode, NodeConfig};
use super::utils::{expand_env_vars, expand_tilde};
#[test]
fn test_expand_env_vars() {
unsafe {
std::env::set_var("TEST_VAR", "test_value");
std::env::set_var("TEST_USER", "testuser");
}
assert_eq!(expand_env_vars("Hello ${TEST_VAR}!"), "Hello test_value!");
assert_eq!(expand_env_vars("${TEST_USER}@host"), "testuser@host");
assert_eq!(expand_env_vars("Hello $TEST_VAR!"), "Hello test_value!");
assert_eq!(expand_env_vars("$TEST_USER@host"), "testuser@host");
assert_eq!(
expand_env_vars("${TEST_USER}:$TEST_VAR"),
"testuser:test_value"
);
assert_eq!(expand_env_vars("${NONEXISTENT}"), "${NONEXISTENT}");
assert_eq!(expand_env_vars("$NONEXISTENT"), "$NONEXISTENT");
assert_eq!(expand_env_vars("no variables here"), "no variables here");
}
#[test]
fn test_expand_tilde() {
let original_home = std::env::var("HOME").ok();
std::env::set_var("HOME", "/home/user");
let path = Path::new("~/.ssh/config");
let expanded = expand_tilde(path);
if let Some(home) = original_home {
std::env::set_var("HOME", home);
} else {
std::env::remove_var("HOME");
}
assert_eq!(expanded, PathBuf::from("/home/user/.ssh/config"));
}
#[test]
fn test_config_parsing() {
let yaml = r#"
defaults:
user: admin
port: 22
ssh_key: ~/.ssh/id_rsa
interactive:
default_mode: multiplex
prompt_format: "[{node}] $ "
history_file: ~/.bssh_history
show_timestamps: true
colors:
node1: red
node2: blue
keybindings:
switch_node: "Ctrl+T"
broadcast_toggle: "Ctrl+A"
clusters:
production:
nodes:
- web1.example.com
- web2.example.com:2222
- user@web3.example.com
ssh_key: ~/.ssh/prod_key
interactive:
default_mode: single_node
prompt_format: "prod> "
staging:
nodes:
- host: staging1.example.com
port: 2200
user: deploy
- staging2.example.com
user: staging_user
"#;
let config: Config = serde_yaml::from_str(yaml).unwrap();
assert_eq!(config.defaults.user, Some("admin".to_string()));
assert_eq!(config.clusters.len(), 2);
assert!(matches!(
config.interactive.default_mode,
InteractiveMode::Multiplex
));
assert_eq!(config.interactive.prompt_format, "[{node}] $ ");
assert_eq!(
config.interactive.history_file,
Some("~/.bssh_history".to_string())
);
assert!(config.interactive.show_timestamps);
assert_eq!(
config.interactive.colors.get("node1"),
Some(&"red".to_string())
);
assert_eq!(config.interactive.keybindings.switch_node, "Ctrl+T");
let prod_cluster = config.get_cluster("production").unwrap();
assert_eq!(prod_cluster.nodes.len(), 3);
assert_eq!(
prod_cluster.defaults.ssh_key,
Some("~/.ssh/prod_key".to_string())
);
let prod_interactive = prod_cluster.interactive.as_ref().unwrap();
assert!(matches!(
prod_interactive.default_mode,
InteractiveMode::SingleNode
));
assert_eq!(prod_interactive.prompt_format, "prod> ");
}
#[test]
fn test_interactive_config_fallback() {
let yaml = r#"
interactive:
default_mode: multiplex
prompt_format: "global> "
show_timestamps: true
clusters:
with_override:
nodes:
- host1
interactive:
default_mode: multiplex
prompt_format: "override> "
without_override:
nodes:
- host2
"#;
let config: Config = serde_yaml::from_str(yaml).unwrap();
let with_override = config.get_interactive_config(Some("with_override"));
assert_eq!(with_override.prompt_format, "override> ");
assert!(matches!(
with_override.default_mode,
InteractiveMode::Multiplex
));
let without_override = config.get_interactive_config(Some("without_override"));
assert_eq!(without_override.prompt_format, "global> ");
assert!(matches!(
without_override.default_mode,
InteractiveMode::Multiplex
));
assert!(without_override.show_timestamps);
let global = config.get_interactive_config(None);
assert_eq!(global.prompt_format, "global> ");
assert!(matches!(global.default_mode, InteractiveMode::Multiplex));
}
#[test]
fn test_backendai_env_parsing() {
unsafe {
std::env::set_var("BACKENDAI_CLUSTER_HOSTS", "sub1,main1");
std::env::set_var("BACKENDAI_CLUSTER_HOST", "main1");
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "main");
std::env::set_var("USER", "testuser");
}
let cluster = Config::from_backendai_env().unwrap();
assert_eq!(cluster.nodes.len(), 2);
match &cluster.nodes[0] {
NodeConfig::Simple(host) => {
assert_eq!(host, "testuser@sub1:2200");
}
_ => panic!("Expected Simple node config"),
}
unsafe {
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "sub");
}
let cluster = Config::from_backendai_env().unwrap();
assert_eq!(cluster.nodes.len(), 1);
match &cluster.nodes[0] {
NodeConfig::Simple(host) => {
assert_eq!(host, "testuser@main1:2200");
}
_ => panic!("Expected Simple node config"),
}
unsafe {
std::env::remove_var("BACKENDAI_CLUSTER_HOSTS");
std::env::remove_var("BACKENDAI_CLUSTER_HOST");
std::env::remove_var("BACKENDAI_CLUSTER_ROLE");
}
}