use susshi::config::{ConnectionMode, ResolvedServer};
use susshi::ssh::client::build_ssh_args;
fn base_server() -> ResolvedServer {
ResolvedServer {
namespace: String::new(),
group_name: "integration".into(),
env_name: "test".into(),
name: "srv".into(),
host: "192.168.1.10".into(),
user: "ops".into(),
port: 22,
ssh_key: String::new(),
ssh_options: vec![],
default_mode: ConnectionMode::Direct,
jump_host: None,
bastion_host: None,
bastion_user: None,
bastion_template: "{target_user}@%n:SSH:{bastion_user}".into(),
use_system_ssh_config: false,
probe_filesystems: vec![],
tunnels: vec![],
tags: vec![],
control_master: false,
control_path: String::new(),
control_persist: "10m".to_string(),
pre_connect_hook: None,
post_disconnect_hook: None,
hook_timeout_secs: 5,
}
}
#[test]
fn direct_minimal() {
let s = base_server();
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
assert!(args.contains(&"-F".to_string()), "-F attendu");
assert!(args.contains(&"/dev/null".to_string()), "/dev/null attendu");
assert!(
args.contains(&"ops@192.168.1.10".to_string()),
"destination attendue"
);
assert!(
!args.contains(&"-p".to_string()),
"-p inattendu pour port 22"
);
assert!(!args.contains(&"-i".to_string()), "-i inattendu sans clé");
assert!(!args.contains(&"-v".to_string()), "-v inattendu");
}
#[test]
fn direct_with_key() {
let mut s = base_server();
s.ssh_key = "~/.ssh/id_ed25519".into();
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
let i_pos = args.iter().position(|a| a == "-i").expect("-i attendu");
assert!(
!args[i_pos + 1].starts_with('~'),
"le tilde doit être expandé"
);
assert!(
args[i_pos + 1].ends_with("/.ssh/id_ed25519"),
"chemin de clé incorrect"
);
}
#[test]
fn direct_with_port() {
let mut s = base_server();
s.port = 2222;
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
let p_pos = args.iter().position(|a| a == "-p").expect("-p attendu");
assert_eq!(args[p_pos + 1], "2222", "valeur du port incorrecte");
assert_eq!(
args.last().unwrap(),
"ops@192.168.1.10",
"destination incorrecte"
);
}
#[test]
fn direct_with_port_in_host_string() {
let mut s = base_server();
s.host = "192.168.1.10:2222".into();
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
assert!(args.contains(&"-p".to_string()), "-p attendu");
assert!(args.contains(&"2222".to_string()), "valeur 2222 attendue");
assert_eq!(args.last().unwrap(), "ops@192.168.1.10");
}
#[test]
fn direct_with_options() {
let mut s = base_server();
s.ssh_options = vec!["ServerAliveInterval=30".into(), "-T".into()];
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
let o_pos = args.iter().position(|a| a == "-o").expect("-o attendu");
assert_eq!(
args[o_pos + 1],
"ServerAliveInterval=30",
"option scalaire incorrecte"
);
assert!(
args.contains(&"-T".to_string()),
"flag -T doit passer tel quel"
);
}
#[test]
fn system_ssh_config() {
let mut s = base_server();
s.use_system_ssh_config = true;
let args = build_ssh_args(&s, ConnectionMode::Direct, false).unwrap();
assert!(
!args.contains(&"-F".to_string()),
"-F ne doit pas être présent quand use_system_ssh_config=true"
);
}
#[test]
fn jump_host() {
let mut s = base_server();
s.jump_host = Some("jops@jump.infra.example.com".into());
let args = build_ssh_args(&s, ConnectionMode::Jump, false).unwrap();
let j_pos = args.iter().position(|a| a == "-J").expect("-J attendu");
assert_eq!(args[j_pos + 1], "jops@jump.infra.example.com");
assert_eq!(args.last().unwrap(), "ops@192.168.1.10");
}
#[test]
fn jump_no_host() {
let s = base_server(); let err = build_ssh_args(&s, ConnectionMode::Jump, false).unwrap_err();
assert!(
err.to_string().contains("Jump host not configured"),
"message d'erreur attendu, obtenu : {}",
err
);
}
#[test]
fn wallix_template() {
let mut s = base_server();
s.bastion_host = Some("bastion.corp.example.com".into());
s.bastion_user = Some("bops".into());
let args = build_ssh_args(&s, ConnectionMode::Wallix, false).unwrap();
let l_pos = args.iter().position(|a| a == "-l").expect("-l attendu");
assert_eq!(
args[l_pos + 1],
"ops@192.168.1.10:SSH:bops",
"template Wallix incorrect"
);
assert!(
args.contains(&"bastion.corp.example.com".to_string()),
"bastion host absent"
);
}
#[test]
fn wallix_no_host() {
let s = base_server(); let err = build_ssh_args(&s, ConnectionMode::Wallix, false).unwrap_err();
assert!(
err.to_string().contains("Wallix host not configured"),
"message d'erreur attendu, obtenu : {}",
err
);
}
#[test]
fn destination_is_last() {
let mut s = base_server();
s.ssh_key = "~/.ssh/id_ed25519".into();
s.ssh_options = vec![
"StrictHostKeyChecking=no".into(),
"-T".into(),
"BatchMode=yes".into(),
];
s.port = 22222;
let args = build_ssh_args(&s, ConnectionMode::Direct, true).unwrap();
assert_eq!(
args.last().unwrap(),
"ops@192.168.1.10",
"Direct : destination doit être en dernière position"
);
let mut s2 = base_server();
s2.ssh_key = "~/.ssh/prod_ed25519".into();
s2.host = "192.168.1.10:22".into();
s2.jump_host = Some("jops@jump.example.com:2222".into());
let args2 = build_ssh_args(&s2, ConnectionMode::Jump, false).unwrap();
assert_eq!(
args2.last().unwrap(),
"ops@192.168.1.10",
"Jump : destination doit être en dernière position"
);
}