use qssh::{QsshConfig, QsshClient, QsshServer, PqAlgorithm};
use qssh::server::QsshServerConfig;
use qssh::transport::AuthMethod;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::time::{timeout, Duration};
use tokio::net::TcpListener;
async fn get_free_port() -> u16 {
let listener = TcpListener::bind("127.0.0.1:0").await
.expect("Failed to bind to random port");
let port = listener.local_addr().unwrap().port();
drop(listener); tokio::time::sleep(Duration::from_millis(10)).await; port
}
#[tokio::test]
async fn test_real_client_server_connection() {
let _ = env_logger::try_init();
println!("Starting real client/server integration test");
let port = get_free_port().await;
let server_addr = format!("127.0.0.1:{}", port);
println!("Using port {} for test server", port);
let mut server_config = QsshServerConfig::new(&server_addr)
.expect("Failed to create server config");
use sha3::{Sha3_256, Digest};
let mut hasher = Sha3_256::new();
hasher.update(b"testpass123");
let password_hash = hasher.finalize().to_vec();
server_config.add_user("testuser", AuthMethod::Password { password_hash });
let server = Arc::new(QsshServer::new(server_config.clone()));
let server_running = Arc::new(Mutex::new(true));
let server_running_clone = server_running.clone();
let server_addr_clone = server_addr.clone();
let server_handle = {
let server = server.clone();
tokio::spawn(async move {
println!("Server starting on {}", server_addr_clone);
match server.start().await {
Ok(_) => println!("Server exited normally"),
Err(e) => {
if *server_running_clone.lock().await {
eprintln!("Server error: {}", e);
}
}
}
})
};
tokio::time::sleep(Duration::from_millis(500)).await;
let client_config = QsshConfig {
server: server_addr.clone(),
username: "testuser".to_string(),
password: Some("testpass123".to_string()),
port_forwards: vec![],
use_qkd: false, pq_algorithm: PqAlgorithm::Falcon512,
key_rotation_interval: 3600,
};
println!("Creating client to connect to {}", server_addr);
let mut client = QsshClient::new(client_config);
let connect_result = timeout(
Duration::from_secs(5),
client.connect()
).await;
match connect_result {
Ok(Ok(_)) => {
println!("Client connected successfully!");
let test_data = b"Hello from client!";
match client.send_data(test_data).await {
Ok(_) => println!("Data sent successfully"),
Err(e) => eprintln!("Failed to send data: {}", e),
}
match timeout(Duration::from_secs(2), client.receive_data()).await {
Ok(Ok(data)) => {
println!("Received {} bytes from server", data.len());
}
Ok(Err(e)) => eprintln!("Failed to receive data: {}", e),
Err(_) => eprintln!("Timeout waiting for server response"),
}
match client.disconnect().await {
Ok(_) => println!("Client disconnected cleanly"),
Err(e) => eprintln!("Error during disconnect: {}", e),
}
}
Ok(Err(e)) => {
eprintln!("Client connection failed: {}", e);
}
Err(_) => {
eprintln!("Connection timeout - server may not be accepting connections");
}
}
*server_running.lock().await = false;
server_handle.abort();
tokio::time::sleep(Duration::from_millis(100)).await;
println!("Test completed");
}
#[tokio::test]
async fn test_port_forwarding() {
let _ = env_logger::try_init();
println!("Testing port forwarding functionality");
let server_port = get_free_port().await;
let local_forward_port = get_free_port().await;
let remote_forward_port = get_free_port().await;
let server_addr = format!("127.0.0.1:{}", server_port);
let mut server_config = QsshServerConfig::new(&server_addr)
.expect("Failed to create server config");
{
use sha3::{Sha3_256, Digest};
let mut hasher = Sha3_256::new();
hasher.update(b"testpass123");
let password_hash = hasher.finalize().to_vec();
server_config.add_user("testuser", AuthMethod::Password { password_hash });
}
let server = Arc::new(QsshServer::new(server_config));
let server_handle = {
let server = server.clone();
tokio::spawn(async move {
let _ = server.start().await;
})
};
tokio::time::sleep(Duration::from_millis(500)).await;
use qssh::PortForward;
let client_config = QsshConfig {
server: server_addr.clone(),
username: "testuser".to_string(),
password: Some("testpass123".to_string()),
port_forwards: vec![
PortForward {
local_port: local_forward_port,
remote_host: "localhost".to_string(),
remote_port: remote_forward_port,
}
],
use_qkd: false,
pq_algorithm: PqAlgorithm::Falcon512,
key_rotation_interval: 3600,
};
let mut client = QsshClient::new(client_config);
match timeout(Duration::from_secs(5), client.connect()).await {
Ok(Ok(_)) => {
println!("Client connected with port forwarding");
let _ = client.disconnect().await;
}
Ok(Err(e)) => {
eprintln!("Failed to set up port forwarding: {}", e);
}
Err(_) => {
eprintln!("Timeout setting up port forwarding");
}
}
server_handle.abort();
tokio::time::sleep(Duration::from_millis(100)).await;
}
#[tokio::test]
async fn test_key_rotation() {
let _ = env_logger::try_init();
println!("Testing key rotation mechanism");
let port = get_free_port().await;
let server_addr = format!("127.0.0.1:{}", port);
let mut server_config = QsshServerConfig::new(&server_addr)
.expect("Failed to create server config");
{
use sha3::{Sha3_256, Digest};
let mut hasher = Sha3_256::new();
hasher.update(b"testpass123");
let password_hash = hasher.finalize().to_vec();
server_config.add_user("testuser", AuthMethod::Password { password_hash });
}
server_config.key_rotation_interval = 2;
let server = Arc::new(QsshServer::new(server_config));
let server_handle = {
let server = server.clone();
tokio::spawn(async move {
let _ = server.start().await;
})
};
tokio::time::sleep(Duration::from_millis(500)).await;
let client_config = QsshConfig {
server: server_addr,
username: "testuser".to_string(),
password: Some("testpass123".to_string()),
port_forwards: vec![],
use_qkd: false,
pq_algorithm: PqAlgorithm::Falcon512,
key_rotation_interval: 2,
};
let mut client = QsshClient::new(client_config);
match timeout(Duration::from_secs(5), client.connect()).await {
Ok(Ok(_)) => {
println!("Connected, waiting for key rotation...");
tokio::time::sleep(Duration::from_secs(3)).await;
match client.send_data(b"Test after rotation").await {
Ok(_) => println!("Data sent successfully after key rotation"),
Err(e) => eprintln!("Failed to send after rotation: {}", e),
}
let _ = client.disconnect().await;
}
_ => {
eprintln!("Failed to connect for key rotation test");
}
}
server_handle.abort();
}
#[tokio::test]
#[ignore = "QKD requires special setup"]
async fn test_qkd_integration() {
let _ = env_logger::try_init();
println!("Testing QKD integration");
let port = get_free_port().await;
let server_addr = format!("127.0.0.1:{}", port);
let mut server_config = QsshServerConfig::new(&server_addr)
.expect("Failed to create server config");
{
use sha3::{Sha3_256, Digest};
let mut hasher = Sha3_256::new();
hasher.update(b"testpass123");
let password_hash = hasher.finalize().to_vec();
server_config.add_user("testuser", AuthMethod::Password { password_hash });
}
server_config.enable_qkd = true;
let server = Arc::new(QsshServer::new(server_config));
let server_handle = {
let server = server.clone();
tokio::spawn(async move {
let _ = server.start().await;
})
};
tokio::time::sleep(Duration::from_millis(500)).await;
let client_config = QsshConfig {
server: server_addr,
username: "testuser".to_string(),
password: Some("testpass123".to_string()),
port_forwards: vec![],
use_qkd: true, pq_algorithm: PqAlgorithm::Falcon512,
key_rotation_interval: 3600,
};
let mut client = QsshClient::new(client_config);
match timeout(Duration::from_secs(10), client.connect()).await {
Ok(Ok(_)) => {
println!("Connected with QKD enabled!");
if client.is_qkd_active() {
println!("QKD is active on the connection");
} else {
eprintln!("Warning: QKD not active despite being enabled");
}
let _ = client.disconnect().await;
}
Ok(Err(e)) => {
eprintln!("Failed to connect with QKD: {}", e);
}
Err(_) => {
eprintln!("Timeout connecting with QKD");
}
}
server_handle.abort();
}