use bssh::commands::interactive_signal::{
TerminalGuard, is_interrupted, reset_interrupt, setup_signal_handlers,
};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
#[test]
fn test_interrupt_flag_operations() {
reset_interrupt();
assert!(!is_interrupted(), "Flag should be false after reset");
reset_interrupt();
assert!(!is_interrupted());
}
#[test]
fn test_terminal_guard_creation_and_drop() {
{
let _guard = TerminalGuard::new();
}
}
#[tokio::test]
async fn test_signal_handler_setup() {
let shutdown = setup_signal_handlers();
assert!(shutdown.is_ok(), "Signal handler setup should succeed");
let shutdown_flag = shutdown.unwrap();
assert!(
!shutdown_flag.load(Ordering::Relaxed),
"Shutdown flag should be false initially"
);
}
#[tokio::test]
async fn test_shutdown_flag_coordination() {
let shutdown = Arc::new(AtomicBool::new(false));
let shutdown_clone = Arc::clone(&shutdown);
let handle = tokio::spawn(async move {
let mut iterations = 0;
while !shutdown_clone.load(Ordering::Relaxed) && iterations < 100 {
tokio::time::sleep(Duration::from_millis(10)).await;
iterations += 1;
}
iterations
});
tokio::time::sleep(Duration::from_millis(50)).await;
shutdown.store(true, Ordering::Relaxed);
let iterations = handle.await.unwrap();
assert!(iterations < 100, "Task should exit before max iterations");
assert!(
iterations >= 4,
"Task should run for some iterations before shutdown"
);
}
#[cfg(unix)]
#[tokio::test]
async fn test_terminal_resize_handler() {
use bssh::commands::interactive_signal::handle_terminal_resize;
let result = handle_terminal_resize().await;
assert!(
result.is_ok(),
"Terminal resize handler should set up successfully"
);
let mut resize_rx = result.unwrap();
let timeout_result = tokio::time::timeout(Duration::from_millis(100), resize_rx.recv()).await;
assert!(
timeout_result.is_err(),
"Should timeout when no resize signal"
);
}
#[test]
fn test_terminal_restoration_on_panic() {
std::panic::catch_unwind(|| {
let _guard = TerminalGuard::new();
std::thread::sleep(Duration::from_millis(10));
})
.expect("Terminal guard should not panic during normal operation");
}
struct MockInteractiveSession {
shutdown: Arc<AtomicBool>,
commands_received: Vec<String>,
}
impl MockInteractiveSession {
fn new() -> Self {
Self {
shutdown: Arc::new(AtomicBool::new(false)),
commands_received: Vec::new(),
}
}
async fn run(&mut self) -> Result<usize, anyhow::Error> {
let mut commands = 0;
while !self.shutdown.load(Ordering::Relaxed) && !is_interrupted() {
tokio::time::sleep(Duration::from_millis(10)).await;
if commands < 5 {
self.commands_received.push(format!("command_{commands}"));
commands += 1;
}
}
Ok(commands)
}
}
#[tokio::test]
async fn test_mock_session_with_shutdown() {
let mut session = MockInteractiveSession::new();
let shutdown_clone = Arc::clone(&session.shutdown);
let handle = tokio::spawn(async move { session.run().await });
tokio::time::sleep(Duration::from_millis(30)).await;
shutdown_clone.store(true, Ordering::Relaxed);
let result = handle.await.unwrap();
assert!(result.is_ok(), "Session should complete successfully");
let commands = result.unwrap();
assert!(commands > 0, "Should have processed some commands");
assert!(commands <= 5, "Should not exceed max commands");
}