use bssh::node::Node;
#[derive(Debug, Clone)]
struct MockNodeSession {
#[allow(dead_code)]
node: Node,
is_connected: bool,
is_active: bool,
commands_received: Vec<String>,
}
impl MockNodeSession {
fn new(host: &str, port: u16, user: &str) -> Self {
Self {
node: Node::new(host.to_string(), port, user.to_string()),
is_connected: true,
is_active: true,
commands_received: vec![],
}
}
fn send_command(&mut self, command: &str) -> Result<(), String> {
if !self.is_connected {
return Err("Not connected".to_string());
}
self.commands_received.push(command.to_string());
Ok(())
}
}
#[test]
fn test_broadcast_command_parsing() {
let commands = vec![
("!broadcast ls -la", true, Some("ls -la")),
("!broadcast echo hello", true, Some("echo hello")),
("!broadcast", false, None), ("!broadcast ", false, None), ("!broadcast test", true, Some("test")), ("broadcast ls", false, None), ("!broadcastls", false, None), ("!all", false, None), ];
for (cmd, is_broadcast, expected_cmd) in commands {
let starts_with_broadcast = cmd.trim().starts_with("!broadcast ");
assert_eq!(starts_with_broadcast, is_broadcast, "Failed for: {cmd}");
if is_broadcast {
let extracted = cmd
.trim()
.strip_prefix("!broadcast ")
.map(|s| s.trim())
.filter(|s| !s.is_empty());
assert_eq!(
extracted, expected_cmd,
"Command extraction failed for: {cmd}"
);
}
}
}
#[test]
fn test_broadcast_to_all_nodes() {
let mut sessions = vec![
MockNodeSession::new("host1", 22, "user"),
MockNodeSession::new("host2", 22, "user"),
MockNodeSession::new("host3", 22, "user"),
];
sessions[0].is_active = true;
sessions[1].is_active = false;
sessions[2].is_active = false;
let saved_states: Vec<bool> = sessions.iter().map(|s| s.is_active).collect();
for session in &mut sessions {
if session.is_connected {
session.is_active = true;
}
}
let command = "uptime";
for session in &mut sessions {
if session.is_connected && session.is_active {
session.send_command(command).unwrap();
}
}
assert_eq!(sessions[0].commands_received.len(), 1);
assert_eq!(sessions[1].commands_received.len(), 1);
assert_eq!(sessions[2].commands_received.len(), 1);
assert_eq!(sessions[0].commands_received[0], "uptime");
assert_eq!(sessions[1].commands_received[0], "uptime");
assert_eq!(sessions[2].commands_received[0], "uptime");
for (session, was_active) in sessions.iter_mut().zip(saved_states.iter()) {
session.is_active = *was_active;
}
assert!(sessions[0].is_active);
assert!(!sessions[1].is_active);
assert!(!sessions[2].is_active);
}
#[test]
fn test_broadcast_with_disconnected_nodes() {
let mut sessions = vec![
MockNodeSession::new("host1", 22, "user"),
MockNodeSession::new("host2", 22, "user"),
MockNodeSession::new("host3", 22, "user"),
];
sessions[1].is_connected = false;
sessions[0].is_active = true;
sessions[1].is_active = false;
sessions[2].is_active = false;
for session in &mut sessions {
if session.is_connected {
session.is_active = true;
}
}
let command = "hostname";
let mut successful_sends = 0;
for session in &mut sessions {
if session.is_connected && session.is_active && session.send_command(command).is_ok() {
successful_sends += 1;
}
}
assert_eq!(successful_sends, 2);
assert_eq!(sessions[0].commands_received.len(), 1);
assert_eq!(sessions[1].commands_received.len(), 0); assert_eq!(sessions[2].commands_received.len(), 1);
}
#[test]
fn test_broadcast_state_restoration() {
let mut sessions = vec![
MockNodeSession::new("host1", 22, "user"),
MockNodeSession::new("host2", 22, "user"),
MockNodeSession::new("host3", 22, "user"),
MockNodeSession::new("host4", 22, "user"),
];
sessions[0].is_active = true;
sessions[1].is_active = false;
sessions[2].is_active = true;
sessions[3].is_active = false;
let saved_states: Vec<bool> = sessions.iter().map(|s| s.is_active).collect();
for session in &mut sessions {
if session.is_connected {
session.is_active = true;
}
}
assert!(sessions.iter().all(|s| s.is_active));
for (session, was_active) in sessions.iter_mut().zip(saved_states.iter()) {
session.is_active = *was_active;
}
assert!(sessions[0].is_active);
assert!(!sessions[1].is_active);
assert!(sessions[2].is_active);
assert!(!sessions[3].is_active);
}
#[test]
fn test_broadcast_empty_command_handling() {
let valid_empty_broadcasts = vec![
"!broadcast ", "!broadcast \t", "!broadcast \n", ];
for cmd in valid_empty_broadcasts {
let trimmed = cmd.trim();
if trimmed.starts_with("!broadcast ") {
let command_part = trimmed.strip_prefix("!broadcast ").unwrap().trim();
assert!(
command_part.is_empty(),
"Command should be empty for: {cmd:?}"
);
}
}
let invalid_broadcasts = vec![
"!broadcast", "!broadcast ", ];
for cmd in invalid_broadcasts {
assert!(
!cmd.trim().starts_with("!broadcast "),
"Should NOT be valid broadcast format: {cmd:?}"
);
}
}
#[test]
fn test_broadcast_vs_regular_command() {
let mut sessions = vec![
MockNodeSession::new("host1", 22, "user"),
MockNodeSession::new("host2", 22, "user"),
];
sessions[0].is_active = true;
sessions[1].is_active = false;
for session in &mut sessions {
if session.is_connected && session.is_active {
session.send_command("regular_cmd").unwrap();
}
}
assert_eq!(sessions[0].commands_received.len(), 1);
assert_eq!(sessions[1].commands_received.len(), 0);
let saved_states: Vec<bool> = sessions.iter().map(|s| s.is_active).collect();
for session in &mut sessions {
if session.is_connected {
session.is_active = true;
}
}
for session in &mut sessions {
if session.is_connected && session.is_active {
session.send_command("broadcast_cmd").unwrap();
}
}
assert_eq!(sessions[0].commands_received.len(), 2);
assert_eq!(sessions[1].commands_received.len(), 1);
assert_eq!(sessions[0].commands_received[1], "broadcast_cmd");
assert_eq!(sessions[1].commands_received[0], "broadcast_cmd");
for (session, was_active) in sessions.iter_mut().zip(saved_states.iter()) {
session.is_active = *was_active;
}
assert!(sessions[0].is_active);
assert!(!sessions[1].is_active);
}
#[test]
fn test_broadcast_with_no_connected_nodes() {
let mut sessions = vec![
MockNodeSession::new("host1", 22, "user"),
MockNodeSession::new("host2", 22, "user"),
];
sessions[0].is_connected = false;
sessions[1].is_connected = false;
let mut successful_sends = 0;
for session in &mut sessions {
if session.is_connected {
session.is_active = true;
if session.send_command("test").is_ok() {
successful_sends += 1;
}
}
}
assert_eq!(successful_sends, 0);
assert_eq!(sessions[0].commands_received.len(), 0);
assert_eq!(sessions[1].commands_received.len(), 0);
}