use sal_git::*; use std::env; #[test] fn test_git_executor_initialization() { let mut executor = GitExecutor::new(); // Test that executor can be initialized without panicking // Even if Redis is not available, init should handle it gracefully let result = executor.init(); assert!( result.is_ok(), "GitExecutor init should handle Redis unavailability gracefully" ); } #[test] fn test_redis_connection_fallback() { // Test that GitExecutor handles Redis connection failures gracefully // Set an invalid Redis URL to force connection failure env::set_var("REDIS_URL", "redis://invalid-host:9999/0"); let mut executor = GitExecutor::new(); let result = executor.init(); // Should succeed even with invalid Redis URL (graceful fallback) assert!( result.is_ok(), "GitExecutor should handle Redis connection failures gracefully" ); // Cleanup env::remove_var("REDIS_URL"); } #[test] fn test_environment_variable_precedence() { // Test REDIS_URL takes precedence over SAL_REDIS_URL env::set_var("REDIS_URL", "redis://primary:6379/0"); env::set_var("SAL_REDIS_URL", "redis://fallback:6379/1"); // Create executor - should use REDIS_URL (primary) let mut executor = GitExecutor::new(); let result = executor.init(); // Should succeed (even if connection fails, init handles it gracefully) assert!( result.is_ok(), "GitExecutor should handle environment variables correctly" ); // Test with only SAL_REDIS_URL env::remove_var("REDIS_URL"); let mut executor2 = GitExecutor::new(); let result2 = executor2.init(); assert!( result2.is_ok(), "GitExecutor should use SAL_REDIS_URL as fallback" ); // Cleanup env::remove_var("SAL_REDIS_URL"); } #[test] fn test_git_command_argument_validation() { let executor = GitExecutor::new(); // Test with empty arguments let result = executor.execute(&[]); assert!(result.is_err(), "Empty git command should fail"); // Test with invalid git command let result = executor.execute(&["invalid-command"]); assert!(result.is_err(), "Invalid git command should fail"); // Test with malformed URL (should fail due to URL validation, not injection) let result = executor.execute(&["clone", "not-a-url"]); assert!(result.is_err(), "Invalid URL should be rejected"); } #[test] fn test_git_executor_with_valid_commands() { let executor = GitExecutor::new(); // Test git version command (should work if git is available) let result = executor.execute(&["--version"]); match result { Ok(output) => { // If git is available, version should be in output let output_str = String::from_utf8_lossy(&output.stdout); assert!( output_str.contains("git version"), "Git version output should contain 'git version'" ); } Err(_) => { // If git is not available, that's acceptable in test environment println!("Note: Git not available in test environment"); } } } #[test] fn test_credential_helper_environment_setup() { use std::process::Command; // Test that we can create and execute a simple credential helper script let temp_dir = std::env::temp_dir(); let helper_script = temp_dir.join("test_git_helper"); // Create a test credential helper script let script_content = "#!/bin/bash\necho username=testuser\necho password=testpass\n"; // Write the helper script let write_result = std::fs::write(&helper_script, script_content); assert!( write_result.is_ok(), "Should be able to write credential helper script" ); // Make it executable (Unix only) #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mut perms = std::fs::metadata(&helper_script).unwrap().permissions(); perms.set_mode(0o755); let perm_result = std::fs::set_permissions(&helper_script, perms); assert!( perm_result.is_ok(), "Should be able to set script permissions" ); } // Test that the script can be executed #[cfg(unix)] { let output = Command::new(&helper_script).output(); match output { Ok(output) => { let stdout = String::from_utf8_lossy(&output.stdout); assert!( stdout.contains("username=testuser"), "Script should output username" ); assert!( stdout.contains("password=testpass"), "Script should output password" ); } Err(_) => { println!("Note: Could not execute credential helper script (shell not available)"); } } } // Clean up let _ = std::fs::remove_file(&helper_script); } #[test] fn test_redis_url_masking() { // Test that sensitive Redis URLs are properly masked for logging // This tests the internal URL masking functionality // Test URLs with passwords let test_cases = vec![ ("redis://user:password@localhost:6379/0", true), ("redis://localhost:6379/0", false), ("redis://user@localhost:6379/0", false), ("invalid-url", false), ]; for (url, has_password) in test_cases { // Set the Redis URL and create executor std::env::set_var("REDIS_URL", url); let mut executor = GitExecutor::new(); let result = executor.init(); // Should always succeed (graceful handling of connection failures) assert!(result.is_ok(), "GitExecutor should handle URL: {}", url); // The actual masking happens internally during logging // We can't easily test the log output, but we verify the executor handles it if has_password { println!( "Note: Tested URL with password (should be masked in logs): {}", url ); } } // Cleanup std::env::remove_var("REDIS_URL"); }