#![allow(clippy::unwrap_used, clippy::panic)]
use network_protocol::error::ProtocolError;
use network_protocol::protocol::message::Message;
use network_protocol::service::client::Client;
use network_protocol::service::daemon;
use std::net::TcpStream as StdTcpStream;
use tokio::net::TcpListener;
use tokio::sync::oneshot;
use tokio::time::{timeout, Duration};
#[tokio::test]
#[serial_test::serial] async fn test_server_connection_timeout() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap().to_string();
drop(listener);
let (shutdown_tx, shutdown_rx) = oneshot::channel();
let server_addr = addr.clone(); let server_handle = tokio::spawn(async move {
daemon::start_with_shutdown(&server_addr, shutdown_rx)
.await
.unwrap();
});
tokio::time::sleep(Duration::from_millis(100)).await;
let result = StdTcpStream::connect(&addr);
assert!(result.is_ok(), "Should be able to establish raw connection");
tokio::time::sleep(Duration::from_secs(7)).await;
let client_result = timeout(Duration::from_secs(5), Client::connect(&addr)).await;
assert!(client_result.is_ok(), "Client connection timed out");
let mut client = client_result.unwrap().unwrap();
let test_msg = Message::Custom {
command: "test".to_string(),
payload: Vec::new(),
};
let result = client.send(test_msg).await;
assert!(result.is_ok(), "Should get successful response");
let _ = shutdown_tx.send(());
let _ = server_handle.await;
}
#[tokio::test]
#[serial_test::serial] async fn test_client_timeout_detection() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap().to_string();
drop(listener);
let (shutdown_tx, shutdown_rx) = oneshot::channel();
let server_addr = addr.clone(); let server_handle = tokio::spawn(async move {
daemon::start_with_shutdown(&server_addr, shutdown_rx)
.await
.unwrap();
});
tokio::time::sleep(Duration::from_millis(100)).await;
let mut client = Client::connect(&addr).await.unwrap();
let test_msg = Message::Custom {
command: "test".to_string(),
payload: Vec::new(),
};
let result = client.send(test_msg).await;
assert!(result.is_ok(), "Should get successful response");
tokio::time::sleep(Duration::from_millis(100)).await;
let _ = shutdown_tx.send(());
let _ = server_handle.await;
let result = timeout(
Duration::from_secs(20),
client.recv_with_keepalive(Duration::from_secs(15)),
)
.await;
match result {
Ok(Err(ProtocolError::ConnectionTimeout)) => {
}
Ok(Err(ProtocolError::ConnectionClosed)) => {
}
Ok(Err(e)) => {
panic!("Got unexpected error: {e:?}");
}
Err(_) => {
panic!("Test timed out without detecting dead connection");
}
Ok(Ok(_)) => {
panic!("Should not have received a valid message");
}
}
}
#[tokio::test]
#[serial_test::serial] async fn test_keepalive_ping_pong() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap().to_string();
drop(listener);
let (shutdown_tx, shutdown_rx) = oneshot::channel();
let server_addr = addr.clone(); let server_handle = tokio::spawn(async move {
daemon::start_with_shutdown(&server_addr, shutdown_rx)
.await
.unwrap();
});
tokio::time::sleep(Duration::from_millis(100)).await;
let mut client = Client::connect(&addr).await.unwrap();
client.send_keepalive().await.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
let test_msg = Message::Custom {
command: "after_ping_pong".to_string(),
payload: Vec::new(),
};
client.send(test_msg).await.unwrap();
let response = timeout(Duration::from_secs(5), client.recv()).await;
assert!(
response.is_ok(),
"Should get successful response after ping/pong"
);
let _ = shutdown_tx.send(());
let _ = server_handle.await;
}