use sal_net::SshConnectionBuilder; use std::path::PathBuf; use std::time::Duration; #[tokio::test] async fn test_ssh_connection_builder_new() { // Test that builder creates a functional connection with defaults let connection = SshConnectionBuilder::new().build(); // Test that the connection can actually attempt operations // Use an invalid host to verify the connection object works but fails as expected let result = connection.execute("echo test").await; // Should fail because no host is configured, but the connection object should work match result { Ok((exit_code, _)) => assert!(exit_code != 0), // Should fail due to missing host Err(_) => {} // Error is expected when no host is configured } } #[tokio::test] async fn test_ssh_connection_builder_host_functionality() { // Test that setting a host actually affects connection behavior let connection = SshConnectionBuilder::new() .host("nonexistent-host-12345.invalid") .user("testuser") .timeout(Duration::from_millis(100)) .build(); // This should fail because the host doesn't exist let result = connection.execute("echo test").await; match result { Ok((exit_code, _)) => assert!(exit_code != 0), // Should fail Err(_) => {} // Error is expected for invalid hosts } } #[tokio::test] async fn test_ssh_connection_builder_port_functionality() { // Test that setting a custom port affects connection behavior let connection = SshConnectionBuilder::new() .host("127.0.0.1") .port(12345) // Non-standard SSH port that should be closed .user("testuser") .timeout(Duration::from_millis(100)) .build(); // This should fail because port 12345 is not running SSH let result = connection.ping().await; match result { Ok(success) => assert!(!success), // Should fail to connect Err(_) => {} // Error is expected for closed ports } } #[tokio::test] async fn test_ssh_connection_builder_user_functionality() { // Test that setting a user affects connection behavior let connection = SshConnectionBuilder::new() .host("127.0.0.1") .user("nonexistent-user-12345") .timeout(Duration::from_millis(100)) .build(); // This should fail because the user doesn't exist let result = connection.execute("whoami").await; match result { Ok((exit_code, _)) => assert!(exit_code != 0), // Should fail Err(_) => {} // Error is expected for invalid users } } #[tokio::test] async fn test_ssh_connection_builder_identity_file() { // Test that setting an identity file affects connection behavior let path = PathBuf::from("/nonexistent/path/to/key"); let connection = SshConnectionBuilder::new() .host("127.0.0.1") .user("testuser") .identity_file(path) .timeout(Duration::from_millis(100)) .build(); // Test that connection with identity file attempts operations but fails as expected let result = connection.ping().await; // Should fail due to invalid key file or authentication, but connection should work match result { Ok(success) => assert!(!success), // Should fail due to invalid key or auth Err(_) => {} // Error is expected for invalid key file } } #[tokio::test] async fn test_ssh_connection_builder_timeout_functionality() { // Test that timeout setting actually affects connection behavior let short_timeout = Duration::from_secs(1); // More reasonable timeout let connection = SshConnectionBuilder::new() .host("10.255.255.1") // Non-routable IP to trigger timeout .timeout(short_timeout) .build(); let start = std::time::Instant::now(); let result = connection.ping().await; let elapsed = start.elapsed(); // Should timeout reasonably quickly (within 10 seconds) assert!(elapsed < Duration::from_secs(10)); match result { Ok(success) => assert!(!success), // Should timeout/fail Err(_) => {} // Error is expected for timeouts } } #[tokio::test] async fn test_ssh_connection_builder_chaining() { // Test that method chaining works and produces a functional connection let connection = SshConnectionBuilder::new() .host("invalid-host-12345.test") .port(2222) .user("testuser") .timeout(Duration::from_millis(100)) .build(); // Test that the chained configuration actually works let result = connection.ping().await; match result { Ok(success) => assert!(!success), // Should fail to connect to invalid host Err(_) => {} // Error is expected for invalid hosts } } #[tokio::test] async fn test_ssh_execute_invalid_host() { let connection = SshConnectionBuilder::new() .host("this-host-definitely-does-not-exist-12345") .user("testuser") .timeout(Duration::from_secs(1)) .build(); let result = connection.execute("echo 'test'").await; // Should fail because host doesn't exist // Note: This test depends on SSH client being available match result { Ok((exit_code, _output)) => { // SSH might return various exit codes for connection failures assert!(exit_code != 0); // Should not succeed } Err(_) => { // Error is also acceptable (SSH client might not be available) // This is expected behavior for invalid hosts } } } #[tokio::test] async fn test_ssh_execute_localhost_no_auth() { let connection = SshConnectionBuilder::new() .host("localhost") .user("nonexistentuser12345") .timeout(Duration::from_secs(1)) .build(); let result = connection.execute("echo 'test'").await; // Should fail due to authentication/user issues match result { Ok((exit_code, _output)) => { // SSH should fail with non-zero exit code assert!(exit_code != 0); } Err(_) => { // Error is also acceptable (SSH client might not be available) // This is expected behavior for authentication failures } } } #[tokio::test] async fn test_ssh_ping_invalid_host() { let connection = SshConnectionBuilder::new() .host("this-host-definitely-does-not-exist-12345") .user("testuser") .timeout(Duration::from_secs(1)) .build(); let result = connection.ping().await; match result { Ok(success) => { assert!(!success); // Should not succeed } Err(_) => { // Error is also acceptable for invalid hosts // This is expected behavior } } } #[tokio::test] async fn test_ssh_ping_localhost_no_auth() { let connection = SshConnectionBuilder::new() .host("localhost") .user("nonexistentuser12345") .timeout(Duration::from_secs(1)) .build(); let result = connection.ping().await; match result { Ok(success) => { // Should fail due to authentication issues assert!(!success); } Err(_) => { // Error is also acceptable for authentication failures // This is expected behavior } } } #[tokio::test] async fn test_ssh_connection_builder_default_values() { // Test that builder creates connection with reasonable defaults let connection = SshConnectionBuilder::new().build(); // Test that default connection can attempt operations but fails gracefully let result = connection.ping().await; // Should fail because no host is configured, but should handle it gracefully match result { Ok(success) => assert!(!success), // Should fail due to missing host Err(_) => {} // Error is expected when no host is configured } } #[tokio::test] async fn test_ssh_connection_builder_full_config() { // Test builder with all options set let connection = SshConnectionBuilder::new() .host("nonexistent-host-12345.invalid") .port(2222) .user("testuser") .identity_file(PathBuf::from("/nonexistent/path/to/key")) .timeout(Duration::from_millis(100)) .build(); // Test that fully configured connection attempts operations but fails as expected let result = connection.ping().await; // Should fail because host doesn't exist, but all configuration should be applied match result { Ok(success) => assert!(!success), // Should fail due to invalid host Err(_) => {} // Error is expected for invalid host } } // Integration test that requires actual SSH setup // This test is disabled by default as it requires SSH server and keys #[tokio::test] #[ignore] async fn test_ssh_execute_real_connection() { // This test would require: // 1. SSH server running on localhost // 2. Valid SSH keys set up // 3. User account configured let connection = SshConnectionBuilder::new() .host("localhost") .user("testuser") // Replace with actual user .build(); let result = connection.execute("echo 'Hello from SSH'").await; match result { Ok((exit_code, output)) => { assert_eq!(exit_code, 0); assert!(output.contains("Hello from SSH")); } Err(e) => { panic!("SSH execution failed: {}", e); } } }