use sal_net::TcpConnector; use std::net::{IpAddr, Ipv4Addr}; use std::time::Duration; use tokio::net::TcpListener; #[tokio::test] async fn test_tcp_connector_new() { let connector = TcpConnector::new(); // Test that the connector can actually perform operations // Use a port that should be closed to verify the connector works let result = connector .check_port(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 65534) .await; assert!(result.is_ok()); assert!(!result.unwrap()); // Port should be closed } #[tokio::test] async fn test_tcp_connector_with_timeout() { let timeout = Duration::from_millis(100); // Short timeout for testing let connector = TcpConnector::with_timeout(timeout); // Test that the custom timeout is actually used by trying to connect to a non-routable IP // This should timeout quickly with our short timeout let start = std::time::Instant::now(); let result = connector .check_port(IpAddr::V4(Ipv4Addr::new(10, 255, 255, 1)), 80) .await; let elapsed = start.elapsed(); assert!(result.is_ok()); assert!(!result.unwrap()); // Should timeout and return false assert!(elapsed < Duration::from_secs(2)); // Should timeout much faster than default } #[tokio::test] async fn test_tcp_connector_default() { let connector = TcpConnector::default(); // Test that default constructor creates a working connector // Verify it behaves the same as TcpConnector::new() let result = connector .check_port(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 65534) .await; assert!(result.is_ok()); assert!(!result.unwrap()); // Port should be closed // Test that it can also ping (basic functionality test) let ping_result = connector.ping("127.0.0.1").await; assert!(ping_result.is_ok()); // Should not error, regardless of ping success } #[tokio::test] async fn test_check_port_open() { // Start a test server let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); // Keep the listener alive in a background task let _handle = tokio::spawn(async move { loop { if let Ok((stream, _)) = listener.accept().await { drop(stream); // Immediately close the connection } } }); // Give the server a moment to start tokio::time::sleep(Duration::from_millis(10)).await; let connector = TcpConnector::new(); let result = connector.check_port(addr.ip(), addr.port()).await; assert!(result.is_ok()); assert!(result.unwrap()); // Port should be open } #[tokio::test] async fn test_check_port_closed() { let connector = TcpConnector::new(); // Use a port that's very unlikely to be open let result = connector .check_port(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 65534) .await; assert!(result.is_ok()); assert!(!result.unwrap()); // Port should be closed } #[tokio::test] async fn test_check_port_timeout() { let connector = TcpConnector::with_timeout(Duration::from_millis(1)); // Use a non-routable IP to trigger timeout let result = connector .check_port(IpAddr::V4(Ipv4Addr::new(10, 255, 255, 1)), 80) .await; assert!(result.is_ok()); assert!(!result.unwrap()); // Should timeout and return false } #[tokio::test] async fn test_check_multiple_ports() { // Start test servers on multiple ports let listener1 = TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr1 = listener1.local_addr().unwrap(); let listener2 = TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr2 = listener2.local_addr().unwrap(); // Keep listeners alive let _handle1 = tokio::spawn(async move { loop { if let Ok((stream, _)) = listener1.accept().await { drop(stream); } } }); let _handle2 = tokio::spawn(async move { loop { if let Ok((stream, _)) = listener2.accept().await { drop(stream); } } }); tokio::time::sleep(Duration::from_millis(10)).await; let connector = TcpConnector::new(); let ports = vec![addr1.port(), addr2.port(), 65533]; // Two open, one closed let results = connector.check_ports(addr1.ip(), &ports).await; assert!(results.is_ok()); let results = results.unwrap(); assert_eq!(results.len(), 3); // First two should be open, last should be closed assert!(results[0].1); // addr1.port() should be open assert!(results[1].1); // addr2.port() should be open assert!(!results[2].1); // 65533 should be closed } #[tokio::test] async fn test_ping_localhost() { let connector = TcpConnector::new(); // Ping localhost - should work on most systems let result = connector.ping("localhost").await; // Note: This might fail in some environments (containers, etc.) // so we just verify the function doesn't panic and returns a boolean result assert!(result.is_ok()); } #[tokio::test] async fn test_ping_invalid_host() { let connector = TcpConnector::new(); // Ping an invalid hostname let result = connector .ping("this-host-definitely-does-not-exist-12345") .await; assert!(result.is_ok()); assert!(!result.unwrap()); // Should fail to ping invalid host } #[tokio::test] async fn test_ping_timeout() { let connector = TcpConnector::with_timeout(Duration::from_millis(1)); // Use a non-routable IP to trigger timeout let result = connector.ping("10.255.255.1").await; assert!(result.is_ok()); // Result could be true or false depending on system, but shouldn't panic }