🐸 Frogue(Fed)

~ololduck/Frogue

Raw

//! SSH connection throttling integration tests.
//!
//! These tests verify that connection limits and timeouts work correctly.
//!
//! TODO: write an helper to check if stream is closed.
//! TODO: still need to write more accurate tests, but my guess is that we would
//! need to hook into russh. Maybe improve the tests with some timers?

mod support;

use std::net::TcpStream;
use std::time::Duration;

use support::{Server, free_port};

fn spawn_with_env(env: &[(&str, &str)]) -> (Server, u16) {
    let port = free_port();
    let mut server = Server::spawn_with_env(&format!("127.0.0.1:{port}"), env);
    server.wait_for_connection(port);
    let ssh_port = server.ssh_port();
    server.wait_for_connection(ssh_port);
    (server, port)
}

/// A simple SSH client that just connects and waits.
fn connect_ssh(ssh_port: u16) -> TcpStream {
    TcpStream::connect(format!("127.0.0.1:{ssh_port}")).expect("should connect to SSH port")
}

#[test]
fn tui_timeout_disconnects_idle_guest() {
    // Set TUI timeout to 1 second
    let env = [("FROGUE_SSH_TUI_TIMEOUT_SECONDS", "1")];
    let (server, _) = spawn_with_env(&env);
    let ssh_port = server.ssh_port();

    // Connect and let it sit idle
    let _stream = connect_ssh(ssh_port);

    // Wait for timeout + buffer
    std::thread::sleep(Duration::from_secs(2));

    // The connection should have been closed by the server
    // We can't easily test this without implementing SSH protocol,
    // but we can at least verify the server is still running
    let _stream2 = connect_ssh(ssh_port);
}

#[test]
fn guest_idle_timeout_disconnects_guest() {
    // Set guest idle timeout to 1 second
    let env = [("FROGUE_SSH_GUEST_IDLE_TIMEOUT_SECONDS", "1")];
    let (server, _) = spawn_with_env(&env);
    let ssh_port = server.ssh_port();

    // Connect as a guest (unregistered key)
    let _stream = connect_ssh(ssh_port);

    // Wait for timeout + buffer
    std::thread::sleep(Duration::from_secs(2));

    // Server should still be running
    let _stream2 = connect_ssh(ssh_port);
}

#[test]
fn max_guests_limit_rejects_excess() {
    // Allow only 1 guest connection
    let env = [("FROGUE_SSH_MAX_GUEST_CONNECTIONS", "1")];
    let (server, _) = spawn_with_env(&env);
    let ssh_port = server.ssh_port();

    // First guest should connect successfully
    let stream1 = connect_ssh(ssh_port);

    // Second guest should be rejected
    let _stream2 = connect_ssh(ssh_port);
    drop(stream1);
    // Server should still be running
    let _stream3 = connect_ssh(ssh_port);
}

#[test]
fn max_connections_limit_closes_excess() {
    // Allow only 1 total connection
    let env = [("FROGUE_SSH_MAX_CONNECTIONS", "1")];
    let (server, _) = spawn_with_env(&env);
    let ssh_port = server.ssh_port();

    // First connection should succeed
    let stream1 = connect_ssh(ssh_port);

    // Second connection should be closed immediately
    let _stream2 = connect_ssh(ssh_port);
    drop(stream1);

    // Server should still be running
    let _stream3 = connect_ssh(ssh_port);
}